diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/BitstreamReader.h index 6f478b72127..a0bbe9b397b 100644 --- a/include/llvm/Bitcode/BitstreamReader.h +++ b/include/llvm/Bitcode/BitstreamReader.h @@ -58,15 +58,27 @@ public: BitstreamReader() : IgnoreBlockInfoNames(true) { } - BitstreamReader(const unsigned char *Start, const unsigned char *End) { - IgnoreBlockInfoNames = true; + BitstreamReader(const unsigned char *Start, const unsigned char *End) + : IgnoreBlockInfoNames(true) { init(Start, End); } - BitstreamReader(StreamableMemoryObject *bytes) { + BitstreamReader(StreamableMemoryObject *bytes) : IgnoreBlockInfoNames(true) { BitcodeBytes.reset(bytes); } + BitstreamReader(BitstreamReader &&Other) { + *this = std::move(Other); + } + + BitstreamReader &operator=(BitstreamReader &&Other) { + BitcodeBytes = std::move(Other.BitcodeBytes); + // Explicitly swap block info, so that nothing gets destroyed twice. + std::swap(BlockInfoRecords, Other.BlockInfoRecords); + IgnoreBlockInfoNames = Other.IgnoreBlockInfoNames; + return *this; + } + void init(const unsigned char *Start, const unsigned char *End) { assert(((End-Start) & 3) == 0 &&"Bitcode stream not a multiple of 4 bytes"); BitcodeBytes.reset(getNonStreamedMemoryObject(Start, End)); @@ -123,6 +135,15 @@ public: BlockInfoRecords.back().BlockID = BlockID; return BlockInfoRecords.back(); } + + /// Takes block info from the other bitstream reader. + /// + /// This is a "take" operation because BlockInfo records are non-trivial, and + /// indeed rather expensive. + void takeBlockInfo(BitstreamReader &&Other) { + assert(!hasBlockInfoRecords()); + BlockInfoRecords = std::move(Other.BlockInfoRecords); + } }; diff --git a/test/Bitcode/function-encoding-rel-operands.ll b/test/Bitcode/function-encoding-rel-operands.ll index 08e3fc01805..24d6d808286 100644 --- a/test/Bitcode/function-encoding-rel-operands.ll +++ b/test/Bitcode/function-encoding-rel-operands.ll @@ -48,3 +48,5 @@ entry: %2 = icmp eq i32 %1, %a ret i1 %2 } + +; CHECK: Stream type: LLVM IR diff --git a/test/Other/Inputs/block-info-only.bc b/test/Other/Inputs/block-info-only.bc new file mode 100755 index 00000000000..e30ca5f472f Binary files /dev/null and b/test/Other/Inputs/block-info-only.bc differ diff --git a/test/Other/Inputs/has-block-info.bc b/test/Other/Inputs/has-block-info.bc new file mode 100644 index 00000000000..1815db6a087 Binary files /dev/null and b/test/Other/Inputs/has-block-info.bc differ diff --git a/test/Other/Inputs/no-block-info.bc b/test/Other/Inputs/no-block-info.bc new file mode 100755 index 00000000000..e79c276dd47 Binary files /dev/null and b/test/Other/Inputs/no-block-info.bc differ diff --git a/test/Other/bcanalyzer-block-info.txt b/test/Other/bcanalyzer-block-info.txt new file mode 100644 index 00000000000..e66031211b7 --- /dev/null +++ b/test/Other/bcanalyzer-block-info.txt @@ -0,0 +1,32 @@ +RUN: llvm-bcanalyzer -dump %S/Inputs/has-block-info.bc | FileCheck -check-prefix=CHECK -check-prefix=DATA %s +RUN: llvm-bcanalyzer -dump %S/Inputs/no-block-info.bc | FileCheck -check-prefix=UNKNOWN -check-prefix=DATA %s +RUN: llvm-bcanalyzer -dump %S/Inputs/no-block-info.bc -block-info %S/Inputs/block-info-only.bc | FileCheck -check-prefix=CHECK -check-prefix=DATA %s + + CHECK: + CHECK: + CHECK: + CHECK: + CHECK: +UNKNOWN: + CHECK: + CHECK: + CHECK: + CHECK: + CHECK: +UNKNOWN: diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 24ebbc1cb80..f95b2724b10 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -31,6 +31,7 @@ #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Verifier.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -61,6 +62,10 @@ NonSymbolic("non-symbolic", cl::desc("Emit numeric info in dump even if" " symbolic info is available")); +static cl::opt + BlockInfoFilename("block-info", + cl::desc("Use the BLOCK_INFO from the given file")); + namespace { /// CurStreamTypeType - A type for CurStreamType @@ -71,15 +76,11 @@ enum CurStreamTypeType { } -/// CurStreamType - If we can sniff the flavor of this stream, we can produce -/// better dump info. -static CurStreamTypeType CurStreamType; - - /// GetBlockName - Return a symbolic block name if known, otherwise return /// null. static const char *GetBlockName(unsigned BlockID, - const BitstreamReader &StreamFile) { + const BitstreamReader &StreamFile, + CurStreamTypeType CurStreamType) { // Standard blocks for all bitcode files. if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) { if (BlockID == bitc::BLOCKINFO_BLOCK_ID) @@ -115,7 +116,8 @@ static const char *GetBlockName(unsigned BlockID, /// GetCodeName - Return a symbolic code name if known, otherwise return /// null. static const char *GetCodeName(unsigned CodeID, unsigned BlockID, - const BitstreamReader &StreamFile) { + const BitstreamReader &StreamFile, + CurStreamTypeType CurStreamType) { // Standard blocks for all bitcode files. if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) { if (BlockID == bitc::BLOCKINFO_BLOCK_ID) { @@ -316,14 +318,14 @@ static std::map BlockIDStats; /// Error - All bitcode analysis errors go through this function, making this a /// good place to breakpoint if debugging. -static bool Error(const std::string &Err) { +static bool Error(const Twine &Err) { errs() << Err << "\n"; return true; } /// ParseBlock - Read a block, updating statistics, etc. static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, - unsigned IndentLevel) { + unsigned IndentLevel, CurStreamTypeType CurStreamType) { std::string Indent(IndentLevel*2, ' '); uint64_t BlockBitStart = Stream.GetCurrentBitNo(); @@ -349,7 +351,8 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, const char *BlockName = nullptr; if (Dump) { outs() << Indent << "<"; - if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader()))) + if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader(), + CurStreamType))) outs() << BlockName; else outs() << "UnknownBlock" << BlockID; @@ -391,7 +394,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, case BitstreamEntry::SubBlock: { uint64_t SubBlockBitStart = Stream.GetCurrentBitNo(); - if (ParseBlock(Stream, Entry.ID, IndentLevel+1)) + if (ParseBlock(Stream, Entry.ID, IndentLevel+1, CurStreamType)) return true; ++BlockStats.NumSubBlocks; uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo(); @@ -432,12 +435,14 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, if (Dump) { outs() << Indent << " <"; if (const char *CodeName = - GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) + GetCodeName(Code, BlockID, *Stream.getBitStreamReader(), + CurStreamType)) outs() << CodeName; else outs() << "UnknownCode" << Code; if (NonSymbolic && - GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) + GetCodeName(Code, BlockID, *Stream.getBitStreamReader(), + CurStreamType)) outs() << " codeid=" << Code; if (Entry.ID != bitc::UNABBREV_RECORD) outs() << " abbrevid=" << Entry.ID; @@ -475,21 +480,23 @@ static void PrintSize(uint64_t Bits) { (double)Bits/8, (unsigned long)(Bits/32)); } - -/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. -static int AnalyzeBitcode() { +static bool openBitcodeFile(StringRef Path, + std::unique_ptr &MemBuf, + BitstreamReader &StreamFile, + BitstreamCursor &Stream, + CurStreamTypeType &CurStreamType) { // Read the input file. ErrorOr> MemBufOrErr = - MemoryBuffer::getFileOrSTDIN(InputFilename); + MemoryBuffer::getFileOrSTDIN(Path); if (std::error_code EC = MemBufOrErr.getError()) - return Error("Error reading '" + InputFilename + "': " + EC.message()); - MemoryBuffer &MemBuf = *MemBufOrErr.get(); + return Error(Twine("Error reading '") + Path + "': " + EC.message()); + MemBuf = std::move(MemBufOrErr.get()); - if (MemBuf.getBufferSize() & 3) + if (MemBuf->getBufferSize() & 3) return Error("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(); + const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart(); + const unsigned char *EndBufPtr = BufPtr + MemBuf->getBufferSize(); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. @@ -497,8 +504,8 @@ static int AnalyzeBitcode() { if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true)) return Error("Invalid bitcode wrapper header"); - BitstreamReader StreamFile(BufPtr, EndBufPtr); - BitstreamCursor Stream(StreamFile); + StreamFile = BitstreamReader(BufPtr, EndBufPtr); + Stream = BitstreamCursor(StreamFile); StreamFile.CollectBlockInfoNames(); // Read the stream signature. @@ -517,6 +524,48 @@ static int AnalyzeBitcode() { Signature[4] == 0xE && Signature[5] == 0xD) CurStreamType = LLVMIRBitstream; + return false; +} + +/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. +static int AnalyzeBitcode() { + std::unique_ptr StreamBuffer; + BitstreamReader StreamFile; + BitstreamCursor Stream; + CurStreamTypeType CurStreamType; + if (openBitcodeFile(InputFilename, StreamBuffer, StreamFile, Stream, + CurStreamType)) + return true; + + // Read block info from BlockInfoFilename, if specified. + // The block info must be a top-level block. + if (!BlockInfoFilename.empty()) { + std::unique_ptr BlockInfoBuffer; + BitstreamReader BlockInfoFile; + BitstreamCursor BlockInfoCursor; + CurStreamTypeType BlockInfoStreamType; + if (openBitcodeFile(BlockInfoFilename, BlockInfoBuffer, BlockInfoFile, + BlockInfoCursor, BlockInfoStreamType)) + return true; + + while (!BlockInfoCursor.AtEndOfStream()) { + unsigned Code = BlockInfoCursor.ReadCode(); + if (Code != bitc::ENTER_SUBBLOCK) + return Error("Invalid record at top-level in block info file"); + + unsigned BlockID = BlockInfoCursor.ReadSubBlockID(); + if (BlockID == bitc::BLOCKINFO_BLOCK_ID) { + if (BlockInfoCursor.ReadBlockInfoBlock()) + return Error("Malformed BlockInfoBlock in block info file"); + break; + } + + BlockInfoCursor.SkipBlock(); + } + + StreamFile.takeBlockInfo(std::move(BlockInfoFile)); + } + unsigned NumTopBlocks = 0; // Parse the top-level structure. We only allow blocks at the top-level. @@ -527,14 +576,14 @@ static int AnalyzeBitcode() { unsigned BlockID = Stream.ReadSubBlockID(); - if (ParseBlock(Stream, BlockID, 0)) + if (ParseBlock(Stream, BlockID, 0, CurStreamType)) return true; ++NumTopBlocks; } if (Dump) outs() << "\n\n"; - uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT; + uint64_t BufferSizeBits = StreamFile.getBitcodeBytes().getExtent() * CHAR_BIT; // Print a summary of the read file. outs() << "Summary of " << InputFilename << ":\n"; outs() << " Total size: "; @@ -553,7 +602,8 @@ static int AnalyzeBitcode() { for (std::map::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { outs() << " Block ID #" << I->first; - if (const char *BlockName = GetBlockName(I->first, StreamFile)) + if (const char *BlockName = GetBlockName(I->first, StreamFile, + CurStreamType)) outs() << " (" << BlockName << ")"; outs() << ":\n"; @@ -611,7 +661,8 @@ static int AnalyzeBitcode() { outs() << " "; if (const char *CodeName = - GetCodeName(FreqPairs[i].second, I->first, StreamFile)) + GetCodeName(FreqPairs[i].second, I->first, StreamFile, + CurStreamType)) outs() << CodeName << "\n"; else outs() << "UnknownCode" << FreqPairs[i].second << "\n";