+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("malformed bitcode file");
+ case BitstreamEntry::EndBlock: {
+ uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
+ BlockStats.NumBits += BlockBitEnd-BlockBitStart;
+ if (Dump) {
+ 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, Entry.ID, IndentLevel+1))
+ 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) {
+ Stream.ReadAbbrevRecord();
+ ++BlockStats.NumAbbrevs;
+ continue;
+ }
+
+ Record.clear();
+
+ ++BlockStats.NumRecords;
+
+ StringRef Blob;
+ unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
+
+ // 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 (Dump) {
+ outs() << Indent << " <";
+ if (const char *CodeName =
+ GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
+ outs() << CodeName;
+ else
+ outs() << "UnknownCode" << Code;
+ if (NonSymbolic &&
+ GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
+ outs() << " codeid=" << Code;
+ if (Entry.ID != bitc::UNABBREV_RECORD)
+ outs() << " abbrevid=" << Entry.ID;
+
+ for (unsigned i = 0, e = Record.size(); i != e; ++i)
+ outs() << " op" << i << "=" << (int64_t)Record[i];
+
+ outs() << "/>";
+
+ if (Blob.data()) {
+ outs() << " blob data = ";
+ 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";
+ }
+ }
+}
+
+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));
+}
+
+
+/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
+static int AnalyzeBitcode() {
+ // Read the input file.
+ OwningPtr<MemoryBuffer> MemBuf;
+
+ if (error_code ec =
+ MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf))
+ return Error("Error reading '" + InputFilename + "': " + ec.message());
+
+ 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();
+
+ // 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 (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
+ return Error("Invalid bitcode wrapper header");
+
+ BitstreamReader StreamFile(BufPtr, EndBufPtr);
+ BitstreamCursor Stream(StreamFile);
+ StreamFile.CollectBlockInfoNames();
+
+ // Read the stream signature.
+ char Signature[6];
+ Signature[0] = Stream.Read(8);
+ Signature[1] = Stream.Read(8);
+ Signature[2] = Stream.Read(4);
+ Signature[3] = Stream.Read(4);
+ Signature[4] = Stream.Read(4);
+ Signature[5] = Stream.Read(4);
+
+ // Autodetect the file contents, if it is one we know.
+ CurStreamType = UnknownBitstream;
+ if (Signature[0] == 'B' && Signature[1] == 'C' &&
+ Signature[2] == 0x0 && Signature[3] == 0xC &&
+ Signature[4] == 0xE && Signature[5] == 0xD)
+ CurStreamType = LLVMIRBitstream;
+
+ unsigned NumTopBlocks = 0;
+
+ // Parse the top-level structure. We only allow blocks at the top-level.
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code != bitc::ENTER_SUBBLOCK)
+ return Error("Invalid record at top-level");
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ if (ParseBlock(Stream, BlockID, 0))
+ return true;
+ ++NumTopBlocks;
+ }
+
+ if (Dump) outs() << "\n\n";
+
+ uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*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;
+ }
+ 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, StreamFile))
+ 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));
+ std::stable_sort(FreqPairs.begin(), FreqPairs.end());
+ std::reverse(FreqPairs.begin(), FreqPairs.end());
+
+ outs() << "\tRecord Histogram:\n";
+ outs() << "\t\t Count # Bits %% Abv Record Kind\n";
+ for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
+ const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
+
+ outs() << format("\t\t%7d %9lu",
+ RecStats.NumInstances,
+ (unsigned long)RecStats.TotalBits);
+
+ if (RecStats.NumAbbrev)
+ outs() <<
+ format("%7.2f ",
+ (double)RecStats.NumAbbrev/RecStats.NumInstances*100);
+ else
+ outs() << " ";
+
+ if (const char *CodeName =
+ GetCodeName(FreqPairs[i].second, I->first, StreamFile))
+ outs() << CodeName << "\n";
+ else
+ outs() << "UnknownCode" << FreqPairs[i].second << "\n";
+ }
+ outs() << "\n";