aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Schimpf <kschimpf@google.com>2013-11-07 08:54:33 -0800
committerKarl Schimpf <kschimpf@google.com>2013-11-07 08:54:33 -0800
commit2796c5b8a31ea88cc24bf3449a95319928c93519 (patch)
treef0acb725535d733f1988a6e047ef0718ff04bf1c
parent64ad0b18dc627d913a301088e7e517f28ec05d3f (diff)
Factor out bitcode parser from pnacl-bcanalyzer.
Factors out bitcode parser from pnacl-bcanalyzer, so that it can also be used for PNaCl bitcode to bitcode rewriters. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3720 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/48623003
-rw-r--r--include/llvm/Bitcode/NaCl/NaClBitcodeParser.h347
-rw-r--r--lib/Bitcode/NaCl/Reader/CMakeLists.txt1
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeParser.cpp95
-rw-r--r--tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp246
4 files changed, 563 insertions, 126 deletions
diff --git a/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h b/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h
new file mode 100644
index 0000000000..406d9f6a95
--- /dev/null
+++ b/include/llvm/Bitcode/NaCl/NaClBitcodeParser.h
@@ -0,0 +1,347 @@
+//===- NaClBitcodeParser.h -----------------------------------*- C++ -*-===//
+// Low-level bitcode driver to parse PNaCl bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Parses and processes low-level PNaCl bitcode files. Defines class
+// NaClBitcodeParser.
+//
+// The concepts of PNaCl bitcode files are basically the same as for
+// LLVM bitcode files (see http://llvm.org/docs/BitCodeFormat.html for
+// details).
+//
+// The bitstream format is an abstract encoding of structured data,
+// very similar to XML in some ways. Like XML, bitstream files contain
+// tags, and nested structures, and you can parse the file without
+// having to understand the tags. Unlike XML, the bitstream format is
+// a binary encoding, and provides a mechanism for the file to
+// self-describe "abbreviations". Abbreviations are effectively size
+// optimizations for the content.
+//
+// The bitcode file is conceptually a sequence of "blocks", defining
+// the content. Blocks contain a sequence of records and
+// blocks. Nested content is defined using nested blocks. A (data)
+// "record" is a tag, and a vector of (unsigned integer) values.
+//
+// Blocks are identified using Block IDs. Each kind of block has a
+// unique block "ID". Records have two elements:
+//
+// a) A "code" identifying what type of record it is.
+// b) A vector of "values" defining the contents of the record.
+//
+// The bitstream "reader" (defined in NaClBitstreamReader.h) defines
+// the implementation that converts the low-level bit file into
+// records and blocks. The bit stream is processed by moving a
+// "cursor" over the sequence of bits.
+//
+// The bitstream reader assumes that each block/record is read in by
+// first reading the "entry". The entry defines whether it corresponds
+// to one of the following:
+//
+// a) At the beginning of a (possibly nested) block
+// b) At the end of the current block.
+// c) The input defines an abberviation.
+// d) The input defines a record.
+//
+// An entry contains two values, a "kind" and an "ID". The kind
+// defines which of the four cases above occurs. The ID provides
+// identifying information on how to further process the input. For
+// case (a), the ID is the identifier associated with the the block
+// being processed. For case (b) and (c) the ID is ignored. For case
+// (d) the ID identifies the abbreviation that should be used to parse
+// the values.
+//
+// The class NaClBitcodeParser defines a bitcode parser that extracts
+// the blocks and records, which are then processed using virtual
+// callbacks. In general, you will want to implement derived classes
+// for each type of block, so that the corresponding data is processed
+// appropriately.
+//
+// The class NaClBitcodeParser parses a bitcode block, and defines a
+// set of callbacks for that block, including:
+//
+// a) EnterBlock: What to do once we have entered the block.
+// b) ProcessRecord: What to do with each parsed record.
+// c) ProcessAbbrevRecord: What to do with a parsed abbreviation.
+// d) ParseBlock: Parse the (nested) block with the given ID.
+// e) ExitBlock: What to do once we have finished processing the block.
+//
+// Note that a separate instance of NaClBitcodeParser (or a
+// corresponding derived class) is created for each nested block. Each
+// instance is responsible for only parsing a single block. Method
+// ParseBlock creates new instances to parse nested blocks. Method
+// GetEnclosingParser() can be used to refer to the parser associated
+// with the enclosing block.
+//
+// TODO(kschimpf): Define an intermediate derived class of
+// NaClBitcodeParser that defines callbacks based on the actual
+// structure of PNaCl bitcode files. That is, it has callbacks for
+// each of the types of blocks (i.e. module, types, global variables,
+// function, symbol tables etc). This derivied class can then be used
+// as the base class for the bitcode reader.
+//
+// TODO(kschimpf): Currently, the processing of abbreviations is
+// handled by the PNaCl bitstream reader, rather than by the
+// parser. Hence, we currently require defining methods
+// EnterBlockInfo, ExitBlockInfo, and ProcessRecordAbbrev. BlockInfo
+// is a special block that defines abbreviations to be applied to all
+// blocks. Record abbreviations (which are a special kind of record)
+// define abbreviations for a the current block.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
+#define LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
+
+#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+using namespace llvm;
+
+class NaClBitcodeParser;
+
+/// Defines the data associated with reading a block record in the
+/// PNaCl bitcode stream.
+class NaClBitcodeRecord {
+public:
+ /// Type for vector of values representing a record.
+ typedef SmallVector<uint64_t, 64> RecordVector;
+
+ NaClBitcodeRecord(unsigned BlockID, NaClBitstreamCursor &Cursor)
+ : BlockID(BlockID),
+ Cursor(Cursor),
+ StartBit(Cursor.GetCurrentBitNo()) {
+ }
+
+ /// Print the contents out to the given stream (for debugging).
+ void Print(raw_ostream& os) const;
+
+ /// Returns the bitstream reader being used.
+ NaClBitstreamReader &GetReader() const {
+ return *Cursor.getBitStreamReader();
+ }
+
+ /// Returns the cursor position within the bitstream.
+ NaClBitstreamCursor &GetCursor() const {
+ return Cursor;
+ }
+
+ /// Returns the block ID of the record.
+ unsigned GetBlockID() const {
+ return BlockID;
+ }
+
+ /// Returns the kind of entry read from the input stream.
+ unsigned GetEntryKind() const {
+ return Entry.Kind;
+ }
+
+ /// Returns the code value (i.e. selector) associated with the
+ /// record.
+ unsigned GetCode() const {
+ return Code;
+ }
+
+ /// Returns the EntryID (e.g. abbreviation if !=
+ /// naclbitcod::UNABBREV_RECORD) associated with the record. Note:
+ /// for block-enter, block-exit, and define-abbreviation, EntryID is
+ /// not the corresponding abbreviation.
+ unsigned GetEntryID() const {
+ return Entry.ID;
+ }
+
+ /// Returns the (value) record associated with the read record.
+ const RecordVector &GetValues() const {
+ return Values;
+ }
+
+ /// Returns the number of bits in this record.
+ unsigned GetNumBits() const {
+ return GetCursor().GetCurrentBitNo() - StartBit;
+ }
+
+protected:
+ // The block ID associated with this record.
+ unsigned BlockID;
+ // The bitstream cursor defining location within the bitcode file.
+ NaClBitstreamCursor &Cursor;
+ // The entry ID associated with the record.
+ unsigned EntryID;
+ // The selector code associated with the record.
+ unsigned Code;
+ // The sequence of values defining the parsed record.
+ RecordVector Values;
+ // The entry (i.e. value(s) preceding the record that define what
+ // value comes next).
+ NaClBitstreamEntry Entry;
+ // Start bit for the record.
+ uint64_t StartBit;
+
+ /// Returns the position of the start bit for this record.
+ unsigned GetStartBit() const {
+ return StartBit;
+ }
+
+private:
+ // Allows class NaClBitcodeParser to read values into the
+ // record, thereby hiding the details of how to read values.
+ friend class NaClBitcodeParser;
+
+ /// Read bitstream entry. Defines what construct appears next in the
+ /// bitstream.
+ void ReadEntry() {
+ StartBit = GetCursor().GetCurrentBitNo();
+ Entry = GetCursor().advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs);
+ }
+
+ /// Reads in a record's values, if the entry defines a record (Must
+ /// be called after ReadEntry).
+ void ReadValues() {
+ Values.clear();
+ Code = GetCursor().readRecord(Entry.ID, Values);
+ }
+
+ NaClBitcodeRecord(const NaClBitcodeRecord &Rcd) LLVM_DELETED_FUNCTION;
+ void operator=(const NaClBitcodeRecord &Rcd) LLVM_DELETED_FUNCTION;
+};
+
+/// Parses a block in the PNaCL bitcode stream.
+class NaClBitcodeParser {
+public:
+
+ // Creates a parser to parse the the block at the given cursor in
+ // the PNaCl bitcode stream. This instance is a "dummy" instance
+ // that starts the parser.
+ explicit NaClBitcodeParser(NaClBitstreamCursor &Cursor)
+ : EnclosingParser(0),
+ Record(ILLEGAL_BLOCK_ID, Cursor),
+ StartBit(Cursor.GetCurrentBitNo()) {
+ BlockStart = StartBit;
+ }
+
+ virtual ~NaClBitcodeParser();
+
+ /// Reads the (top-level) block associated with the given block
+ /// record at the stream cursor. Returns true if unable to parse.
+ /// Can be called multiple times to parse multiple blocks.
+ bool Parse();
+
+ // Called once the bitstream reader has entered the corresponding
+ // subblock. Argument NumWords is set to the number of words in the
+ // corresponding subblock.
+ virtual void EnterBlock(unsigned NumWords) {}
+
+ // Called when the corresponding EndBlock of the block being parsed
+ // is found.
+ virtual void ExitBlock() {}
+
+ // Called before a BlockInfo block is parsed. Note: BlockInfo blocks
+ // are special. They include abbreviations to be used for blocks.
+ // After this routine is called, the NaClBitstreamParser is called
+ // to parse the BlockInfo block (rather than making a call to
+ // Parser->Parse()).
+ virtual void EnterBlockInfo() {}
+
+ // Called after a BlockInfo block is parsed.
+ virtual void ExitBlockInfo() { ExitBlock(); }
+
+ // Called after each record (within the block) is read (into field Record).
+ virtual void ProcessRecord() {}
+
+ // Called if a block-specific abbreviation is read (into field
+ // Record), after processing by the bitstream reader.
+ virtual void ProcessRecordAbbrev() {}
+
+ // Creates an instance of the NaClBitcodeParser to use to parse the
+ // block with the given block ID, and then call's method
+ // ParseThisBlock() to parse the corresponding block. Note:
+ // Each derived class should define it's own version of this
+ // method, following the pattern below.
+ virtual bool ParseBlock(unsigned BlockID) {
+ // Default implementation just builds a parser that does nothing.
+ NaClBitcodeParser Parser(BlockID, this);
+ return Parser.ParseThisBlock();
+ }
+
+ // Called when error occurs. Message is the error to report. Always
+ // returns true (the error return value of Parse).
+ virtual bool Error(const std::string Message) {
+ errs() << "Error: " << Message << "\n";
+ return true;
+ }
+
+ // Returns the number of bits in this block.
+ unsigned GetNumBits() {
+ return Record.GetCursor().GetCurrentBitNo() - StartBit;
+ }
+
+ // Returns the number of bits in this block, but not subblocks
+ // within this block.
+ unsigned GetLocalNumBits() {
+ return Record.GetCursor().GetCurrentBitNo() - BlockStart;
+ }
+
+ /// Returns the block ID associated with the Parser.
+ unsigned GetBlockID() {
+ return Record.GetBlockID();
+ }
+
+ /// Returns the enclosing block parser of this block.
+ NaClBitcodeParser *GetEnclosingParser() const {
+ // Note: The top-level parser instance is a dummy instance
+ // and is not considered an enclosing parser.
+ return EnclosingParser->EnclosingParser ? EnclosingParser : 0;
+ }
+
+protected:
+ // The containing parser.
+ NaClBitcodeParser *EnclosingParser;
+
+ // The current record (within the block) being processed.
+ NaClBitcodeRecord Record;
+
+ // Creates a block parser to parse the block associated with the
+ // bitcode entry that defines the beginning of a block. This
+ // instance actually parses the corresponding block.
+ NaClBitcodeParser(unsigned BlockID,
+ NaClBitcodeParser *EnclosingParser)
+ : EnclosingParser(EnclosingParser),
+ Record(BlockID, EnclosingParser->Record.GetCursor()),
+ StartBit(EnclosingParser->Record.GetStartBit()) {
+ BlockStart = StartBit;
+ }
+
+ // Parses the block using the parser defined by
+ // ParseBlock(unsigned). Returns true if unable to parse the
+ // block. Note: Should only be called by virtual
+ // ParseBlock(unsigned).
+ bool ParseThisBlock();
+
+private:
+ // Special constant identifying the top-level instance.
+ static const unsigned ILLEGAL_BLOCK_ID = UINT_MAX;
+
+ // The start bit of the block.
+ unsigned StartBit;
+ // The start bit of the block, plus the bits in all subblocks. Used
+ // to compute the number of (block local) bits.
+ unsigned BlockStart;
+
+ // Updates BlockStart in the enclosingblock, so that bits in this
+ // block are not counted as local bits for the enclosing block.
+ void RemoveBlockBitsFromEnclosingBlock() {
+ EnclosingParser->BlockStart += GetNumBits();
+ }
+
+ void operator=(const NaClBitcodeParser &Parser) LLVM_DELETED_FUNCTION;
+ NaClBitcodeParser(const NaClBitcodeParser &Parser) LLVM_DELETED_FUNCTION;
+};
+
+
+#endif
diff --git a/lib/Bitcode/NaCl/Reader/CMakeLists.txt b/lib/Bitcode/NaCl/Reader/CMakeLists.txt
index 9e4de723c1..d2eb93b00a 100644
--- a/lib/Bitcode/NaCl/Reader/CMakeLists.txt
+++ b/lib/Bitcode/NaCl/Reader/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_library(LLVMNaClBitReader
NaClBitcodeHeader.cpp
NaClBitcodeReader.cpp
NaClBitstreamReader.cpp
+ NaClBitcodeParser.cpp
)
add_dependencies(LLVMNaClBitReader intrinsics_gen)
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeParser.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeParser.cpp
new file mode 100644
index 0000000000..642c8cfd34
--- /dev/null
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeParser.cpp
@@ -0,0 +1,95 @@
+//===- NaClBitcodeParser.cpp ----------------------------------------------===//
+// Low-level bitcode driver to parse PNaCl bitcode files.
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "NaClBitcodeParser"
+
+#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
+#include "llvm/Support/Debug.h"
+
+void NaClBitcodeRecord::Print(raw_ostream& os) const {
+ DEBUG(os << "Block " << GetBlockID() << ", Code " << Code
+ << ", EntryID " << Entry.ID << ", <";
+ for (unsigned i = 0, e = Values.size(); i != e; ++i) {
+ if (i > 0) os << " ";
+ os << Values[i];
+ }
+ os << ">");
+}
+
+NaClBitcodeParser::~NaClBitcodeParser() {}
+
+bool NaClBitcodeParser::Parse() {
+ Record.ReadEntry();
+
+ if (Record.GetEntryKind() != NaClBitstreamEntry::SubBlock)
+ return Error("Expected block, but not found");
+
+ return ParseBlock(Record.GetEntryID());
+}
+
+bool NaClBitcodeParser::ParseThisBlock() {
+ if (GetBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
+ // BLOCKINFO is a special part of the stream. Let the bitstream
+ // reader process this block.
+ //
+ // TODO(kschimpf): Move this out of the bitstream reader, so that
+ // we have simplier API's for this class.
+ EnterBlockInfo();
+ if (Record.GetCursor().ReadBlockInfoBlock())
+ return Error("Malformed BlockInfoBlock");
+ RemoveBlockBitsFromEnclosingBlock();
+ ExitBlockInfo();
+ return false;
+ }
+
+ // Regular block. Enter subblock.
+ unsigned NumWords;
+ if (Record.GetCursor().EnterSubBlock(GetBlockID(), &NumWords)) {
+ return Error("Malformed block record");
+ }
+
+ EnterBlock(NumWords);
+
+ // Process records.
+ while (1) {
+ if (Record.GetCursor().AtEndOfStream())
+ return Error("Premature end of bitstream");
+
+ // Read entry defining type of entry.
+ Record.ReadEntry();
+
+ switch (Record.GetEntryKind()) {
+ case NaClBitstreamEntry::Error:
+ return Error("malformed bitcode file");
+ case NaClBitstreamEntry::EndBlock: {
+ ExitBlock();
+ RemoveBlockBitsFromEnclosingBlock();
+ return false;
+ }
+ case NaClBitstreamEntry::SubBlock: {
+ if (ParseBlock(Record.GetEntryID())) return true;
+ break;
+ }
+ case NaClBitstreamEntry::Record:
+ // The interesting case.
+ if (Record.GetEntryID() == naclbitc::DEFINE_ABBREV) {
+ //Process any block-local abbreviation definitions.
+ Record.GetCursor().ReadAbbrevRecord();
+ ProcessRecordAbbrev();
+ } else {
+ // Read in a record.
+ Record.ReadValues();
+ ProcessRecord();
+ }
+ break;
+ }
+ }
+ return false;
+}
diff --git a/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp
index d5f61c14cd..573a3e0573 100644
--- a/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp
+++ b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp
@@ -38,6 +38,7 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
+#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
@@ -330,134 +331,131 @@ static bool Error(const std::string &Err) {
return true;
}
-/// ParseBlock - Read a block, updating statistics, etc.
-static bool ParseBlock(NaClBitstreamCursor &Stream, unsigned BlockID,
- unsigned IndentLevel) {
- std::string Indent(IndentLevel*2, ' ');
- DEBUG(dbgs() << Indent << "-> ParseBlock(" << BlockID << ")\n");
- uint64_t BlockBitStart = Stream.GetCurrentBitNo();
-
- // Get the statistics for this BlockID.
- PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
+// Returns (a cached) string to indent N levels.
+static const std::string &IndentString(unsigned N) {
+ static std::vector<std::string*> IndentLevel;
+ if (N >= IndentLevel.size())
+ IndentLevel.resize(N+1);
+ std::string* Str = IndentLevel[N];
+ if (Str == 0) {
+ Str = new std::string();
+ for (unsigned i = 0; i < N; ++i) {
+ Str->append(" ");
+ }
+ IndentLevel[N] = Str;
+ }
+ return *Str;
+}
- BlockStats.NumInstances++;
+// Parses bitcode blocks, and collects distribution of records in each block.
+// Also dumps bitcode structure if specified (via global variables).
+class PNaClBcanalyzerParser : public NaClBitcodeParser {
+public:
+ explicit PNaClBcanalyzerParser(NaClBitstreamCursor &Cursor)
+ : NaClBitcodeParser(Cursor),
+ IndentLevel(-1),
+ Indent(""),
+ NumWords(0),
+ BlockName(0),
+ BlockStats(0) {
+ }
- // BLOCKINFO is a special part of the stream.
- if (BlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
- if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
- if (Stream.ReadBlockInfoBlock())
- return Error("Malformed BlockInfoBlock");
- uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
- BlockStats.NumBits += BlockBitEnd-BlockBitStart;
- DEBUG(dbgs() << Indent << "<- ParseBlock\n");
- return false;
+ PNaClBcanalyzerParser(unsigned BlockID,
+ PNaClBcanalyzerParser *EnclosingBlock)
+ : NaClBitcodeParser(BlockID, EnclosingBlock),
+ IndentLevel(EnclosingBlock->IndentLevel+1),
+ Indent(IndentString(EnclosingBlock->IndentLevel+1)),
+ NumWords(0),
+ BlockName(0),
+ BlockStats(&BlockIDStats[BlockID])
+ {
+ BlockStats->NumInstances++;
}
- unsigned NumWords = 0;
- if (Stream.EnterSubBlock(BlockID, &NumWords))
- return Error("Malformed block record");
+ virtual ~PNaClBcanalyzerParser() {}
- const char *BlockName = 0;
- if (Dump) {
- outs() << Indent << "<";
- if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader())))
- outs() << BlockName;
- else
- outs() << "UnknownBlock" << BlockID;
+ virtual bool Error(const std::string Message) {
+ // Use local error routine so that all errors are treated uniformly.
+ return ::Error(Message);
+ }
- if (NonSymbolic && BlockName)
- outs() << " BlockID=" << BlockID;
+ // Called once the block has been entered by the bitstream reader.
+ // Argument NumWords is set to the number of words in the
+ // corresponding block.
+ virtual void EnterBlock(unsigned NumberWords) {
+ NumWords = NumberWords;
+ IncrementCallingBlock();
+ BlockName = 0;
+ if (Dump) {
+ unsigned BlockID = GetBlockID();
+ outs() << Indent << "<";
+ if ((BlockName = GetBlockName(BlockID, Record.GetReader())))
+ outs() << BlockName;
+ else
+ outs() << "UnknownBlock" << BlockID;
- if (!Records) {
- outs() << " NumWords=" << NumWords
- << " BlockCodeSize=" << Stream.getAbbrevIDWidth();
- }
- outs() << ">\n";
- }
+ if (NonSymbolic && BlockName)
+ outs() << " BlockID=" << BlockID;
- SmallVector<uint64_t, 64> Record;
-
- // Read all the records for this block.
- while (1) {
- if (Stream.AtEndOfStream())
- return Error("Premature end of bitstream");
-
- uint64_t RecordStartBit = Stream.GetCurrentBitNo();
-
- NaClBitstreamEntry Entry =
- Stream.advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs);
-
- switch (Entry.Kind) {
- case NaClBitstreamEntry::Error:
- return Error("malformed bitcode file");
- case NaClBitstreamEntry::EndBlock: {
- uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
- BlockStats.NumBits += BlockBitEnd-BlockBitStart;
- if (Dump) {
- outs() << Indent << "</";
- if (BlockName)
- outs() << BlockName << ">\n";
- else
- outs() << "UnknownBlock" << BlockID << ">\n";
+ if (!Records) {
+ outs() << " NumWords=" << NumberWords
+ << " BlockCodeSize="
+ << Record.GetCursor().getAbbrevIDWidth();
}
- DEBUG(dbgs() << Indent << "<- ParseBlock\n");
- return false;
- }
-
- case NaClBitstreamEntry::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 NaClBitstreamEntry::Record:
- // The interesting case.
- break;
+ outs() << ">\n";
}
+ }
- if (Entry.ID == naclbitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- ++BlockStats.NumAbbrevs;
- continue;
+ // Called when the corresponding EndBlock of the block being parsed
+ // is found.
+ virtual void ExitBlock() {
+ BlockStats->NumBits += GetLocalNumBits();
+ if (Dump) {
+ outs() << Indent << "</";
+ if (BlockName)
+ outs() << BlockName << ">\n";
+ else
+ outs() << "UnknownBlock" << GetBlockID() << ">\n";
}
-
- Record.clear();
+ }
- ++BlockStats.NumRecords;
+ // Called after a BlockInfo block is parsed.
+ virtual void ExitBlockInfo() {
+ BlockStats->NumBits += GetLocalNumBits();
+ if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
+ IncrementCallingBlock();
+ }
- StringRef Blob;
- unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
+ // Process the last read record in the block.
+ virtual void ProcessRecord() {
+ ++BlockStats->NumRecords;
+ unsigned Code = Record.GetCode();
// 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 != naclbitc::UNABBREV_RECORD) {
- BlockStats.CodeFreq[Code].NumAbbrev++;
- ++BlockStats.NumAbbreviatedRecords;
+ if (BlockStats->CodeFreq.size() <= Code)
+ BlockStats->CodeFreq.resize(Code+1);
+ BlockStats->CodeFreq[Code].NumInstances++;
+ BlockStats->CodeFreq[Code].TotalBits += Record.GetNumBits();
+ if (Record.GetEntryID() != naclbitc::UNABBREV_RECORD) {
+ BlockStats->CodeFreq[Code].NumAbbrev++;
+ ++BlockStats->NumAbbreviatedRecords;
}
if (Dump) {
outs() << Indent << " <";
const char *CodeName =
- GetCodeName(Code, BlockID, *Stream.getBitStreamReader());
+ GetCodeName(Code, GetBlockID(), Record.GetReader());
if (CodeName)
outs() << CodeName;
else
outs() << "UnknownCode" << Code;
if (NonSymbolic && CodeName)
outs() << " codeid=" << Code;
- if (!Records && Entry.ID != naclbitc::UNABBREV_RECORD)
- outs() << " abbrevid=" << Entry.ID;
+ if (!Records && Record.GetEntryID() != naclbitc::UNABBREV_RECORD)
+ outs() << " abbrevid=" << Record.GetEntryID();
- for (unsigned i = 0, e = Record.size(); i != e; ++i) {
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
+ for (unsigned i = 0, e = Values.size(); i != e; ++i) {
if (OpsPerLine && (i % OpsPerLine) == 0 && i > 0) {
outs() << "\n" << Indent << " ";
if (CodeName) {
@@ -467,30 +465,32 @@ static bool ParseBlock(NaClBitstreamCursor &Stream, unsigned BlockID,
outs() << " ";
}
}
- outs() << " op" << i << "=" << (int64_t)Record[i];
+ outs() << " op" << i << "=" << (int64_t)Values[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;
- }
+ outs() << "/>\n";
+ }
+ }
- if (BlobIsPrintable)
- outs() << "'" << Blob << "'";
- else
- outs() << "unprintable, " << Blob.size() << " bytes.";
- }
+ virtual bool ParseBlock(unsigned BlockID) {
+ PNaClBcanalyzerParser Parser(BlockID, this);
+ return Parser.ParseThisBlock();
+ }
- outs() << "\n";
+ int IndentLevel;
+ std::string Indent;
+ unsigned NumWords;
+ const char *BlockName;
+ PerBlockIDStats *BlockStats;
+protected:
+ void IncrementCallingBlock() {
+ if (NaClBitcodeParser *Parser = GetEnclosingParser()) {
+ PNaClBcanalyzerParser *PNaClBlock =
+ static_cast<PNaClBcanalyzerParser*>(Parser);
+ ++PNaClBlock->BlockStats->NumSubBlocks;
}
}
-}
+};
static void PrintSize(double Bits) {
outs() << format("%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32));
@@ -539,17 +539,11 @@ static int AnalyzeBitcode() {
}
if (Header.NumberFields()) outs() << "\n";
+ PNaClBcanalyzerParser Parser(Stream);
// Parse the top-level structure. We only allow blocks at the top-level.
while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code != naclbitc::ENTER_SUBBLOCK)
- return Error("Invalid record at top-level");
-
- unsigned BlockID = Stream.ReadSubBlockID();
-
- if (ParseBlock(Stream, BlockID, 0))
- return true;
++NumTopBlocks;
+ if (Parser.Parse()) return 1;
}
if (Dump) outs() << "\n\n";