Add a new BitstreamEntry concept, and add two helper methods for walking

through a BitstreamCursor that produce it: advance() and 
advanceSkippingSubblocks(), representing the two most common ways clients
want to walk through bitcode.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@172919 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2013-01-19 21:35:24 +00:00
parent 35f63ddc8f
commit 63246aa04f
3 changed files with 94 additions and 9 deletions

View File

@ -27,6 +27,11 @@ namespace llvm {
class Deserializer;
/// BitstreamReader - This class is used to read from an LLVM bitcode stream,
/// maintaining information that is global to decoding the entire file. While
/// a file is being read, multiple cursors can be independently advanced or
/// skipped around within the file. These are represented by the
/// BitstreamCursor class.
class BitstreamReader {
public:
/// BlockInfo - This contains information emitted to BLOCKINFO_BLOCK blocks.
@ -119,9 +124,48 @@ public:
BlockInfoRecords.back().BlockID = BlockID;
return BlockInfoRecords.back();
}
};
/// BitstreamEntry - When advancing through a bitstream cursor, each advance can
/// discover a few different kinds of entries:
/// Error - Malformed bitcode was found.
/// EndBlock - We've reached the end of the current block, (or the end of the
/// file, which is treated like a series of EndBlock records.
/// SubBlock - This is the start of a new subblock of a specific ID.
/// Record - This is a record with a specific AbbrevID.
///
struct BitstreamEntry {
enum {
Error,
EndBlock,
SubBlock,
Record
} Kind;
unsigned ID;
static BitstreamEntry getError() {
BitstreamEntry E; E.Kind = Error; return E;
}
static BitstreamEntry getEndBlock() {
BitstreamEntry E; E.Kind = EndBlock; return E;
}
static BitstreamEntry getSubBlock(unsigned ID) {
BitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E;
}
static BitstreamEntry getRecord(unsigned AbbrevID) {
BitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E;
}
};
/// BitstreamCursor - This represents a position within a bitcode file. There
/// may be multiple independent cursors reading within one bitstream, each
/// maintaining their own local state.
///
/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not
/// be passed by value.
class BitstreamCursor {
friend class Deserializer;
BitstreamReader *BitStream;
@ -151,6 +195,7 @@ class BitstreamCursor {
/// BlockScope - This tracks the codesize of parent blocks.
SmallVector<Block, 8> BlockScope;
public:
BitstreamCursor() : BitStream(0), NextChar(0) {
}
@ -183,9 +228,6 @@ public:
void freeState();
/// GetAbbrevIDWidth - Return the number of bits used to encode an abbrev #.
unsigned GetAbbrevIDWidth() const { return CurCodeSize; }
bool isEndPos(size_t pos) {
return BitStream->getBitcodeBytes().isObjectEnd(static_cast<uint64_t>(pos));
}
@ -212,6 +254,9 @@ public:
return isEndPos(NextChar) && BitsInCurWord == 0;
}
/// getAbbrevIDWidth - Return the number of bits used to encode an abbrev #.
unsigned getAbbrevIDWidth() const { return CurCodeSize; }
/// GetCurrentBitNo - Return the bit # of the bit we are reading.
uint64_t GetCurrentBitNo() const {
return NextChar*CHAR_BIT - BitsInCurWord;
@ -225,6 +270,46 @@ public:
}
/// advance - Advance the current bitstream, returning the next entry in the
/// stream.
BitstreamEntry advance() {
while (1) {
unsigned Code = ReadCode();
if (Code == bitc::END_BLOCK) {
if (ReadBlockEnd())
return BitstreamEntry::getError();
return BitstreamEntry::getEndBlock();
}
if (Code == bitc::ENTER_SUBBLOCK)
return BitstreamEntry::getSubBlock(ReadSubBlockID());
if (Code == bitc::DEFINE_ABBREV) {
// We read and accumulate abbrev's, the client can't do anything with
// them anyway.
ReadAbbrevRecord();
continue;
}
return BitstreamEntry::getRecord(Code);
}
}
/// advanceSkippingSubblocks - This is a convenience function for clients that
/// don't expect any subblocks. This just skips over them automatically.
BitstreamEntry advanceSkippingSubblocks() {
while (1) {
// If we found a normal entry, return it.
BitstreamEntry Entry = advance();
if (Entry.Kind != BitstreamEntry::SubBlock)
return Entry;
// If we found a sub-block, just skip over it and check the next entry.
if (SkipBlock())
return BitstreamEntry::getError();
}
}
/// JumpToBit - Reset the stream to the specified bit number.
void JumpToBit(uint64_t BitNo) {
uintptr_t ByteNo = uintptr_t(BitNo/8) & ~3;
@ -375,12 +460,13 @@ public:
// [END_BLOCK, <align4bytes>]
SkipToWord();
PopBlockScope();
popBlockScope();
return false;
}
private:
void PopBlockScope() {
void popBlockScope() {
CurCodeSize = BlockScope.back().PrevCodeSize;
// Delete abbrevs from popped scope.
@ -443,7 +529,6 @@ public:
//===--------------------------------------------------------------------===//
// Abbrev Processing
//===--------------------------------------------------------------------===//
void ReadAbbrevRecord();
bool ReadBlockInfoBlock();

View File

@ -1737,7 +1737,7 @@ bool BitcodeReader::ParseBitcodeInto(Module *M) {
// The ranlib in xcode 4 will align archive members by appending newlines
// to the end of them. If this file size is a multiple of 4 but not 8, we
// have to read and ignore these final 4 bytes :-(
if (Stream.GetAbbrevIDWidth() == 2 && Code == 2 &&
if (Stream.getAbbrevIDWidth() == 2 && Code == 2 &&
Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a &&
Stream.AtEndOfStream())
return false;

View File

@ -150,7 +150,7 @@ unsigned BitstreamCursor::ReadRecord(unsigned AbbrevID,
// the data, do so to avoid copying it.
if (BlobStart) {
*BlobStart = (const char*)BitStream->getBitcodeBytes().getPointer(
NextChar, NumElts);
NextChar, NumElts);
*BlobLen = NumElts;
} else {
for (; NumElts; ++NextChar, --NumElts)