Index: cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h =================================================================== --- cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h +++ cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h @@ -11,7 +11,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Frontend/SerializedDiagnostics.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" namespace llvm { class raw_ostream; Index: cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h =================================================================== --- cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h +++ cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICREADER_H #include "clang/Basic/LLVM.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorOr.h" #include Index: cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h =================================================================== --- cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h +++ cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h @@ -9,7 +9,7 @@ #ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_ #define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_ -#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitstream/BitCodes.h" namespace clang { namespace serialized_diags { Index: cfe/trunk/include/clang/Serialization/ASTBitCodes.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h @@ -23,7 +23,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitstream/BitCodes.h" #include #include Index: cfe/trunk/include/clang/Serialization/ASTReader.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTReader.h +++ cfe/trunk/include/clang/Serialization/ASTReader.h @@ -56,7 +56,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" Index: cfe/trunk/include/clang/Serialization/ASTWriter.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTWriter.h +++ cfe/trunk/include/clang/Serialization/ASTWriter.h @@ -36,7 +36,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include #include #include Index: cfe/trunk/include/clang/Serialization/Module.h =================================================================== --- cfe/trunk/include/clang/Serialization/Module.h +++ cfe/trunk/include/clang/Serialization/Module.h @@ -24,7 +24,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Endian.h" #include #include Index: cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -21,7 +21,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" Index: cfe/trunk/lib/Frontend/ASTUnit.cpp =================================================================== --- cfe/trunk/lib/Frontend/ASTUnit.cpp +++ cfe/trunk/lib/Frontend/ASTUnit.cpp @@ -75,7 +75,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CrashRecoveryContext.h" Index: cfe/trunk/lib/Frontend/CMakeLists.txt =================================================================== --- cfe/trunk/lib/Frontend/CMakeLists.txt +++ cfe/trunk/lib/Frontend/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS BitReader + BitstreamReader Option ProfileData Support Index: cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp =================================================================== --- cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp +++ cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp @@ -13,8 +13,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" Index: cfe/trunk/lib/Frontend/TestModuleFileExtension.h =================================================================== --- cfe/trunk/lib/Frontend/TestModuleFileExtension.h +++ cfe/trunk/lib/Frontend/TestModuleFileExtension.h @@ -11,7 +11,7 @@ #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include namespace clang { Index: cfe/trunk/lib/Frontend/TestModuleFileExtension.cpp =================================================================== --- cfe/trunk/lib/Frontend/TestModuleFileExtension.cpp +++ cfe/trunk/lib/Frontend/TestModuleFileExtension.cpp @@ -9,7 +9,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Hashing.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/raw_ostream.h" #include using namespace clang; Index: cfe/trunk/lib/Serialization/ASTReader.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp +++ cfe/trunk/lib/Serialization/ASTReader.cpp @@ -101,7 +101,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" Index: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp @@ -57,7 +57,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" Index: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp @@ -52,7 +52,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include Index: cfe/trunk/lib/Serialization/ASTWriter.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp +++ cfe/trunk/lib/Serialization/ASTWriter.cpp @@ -83,8 +83,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DJB.h" Index: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp @@ -21,7 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace serialization; Index: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp @@ -18,7 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Token.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" using namespace clang; //===----------------------------------------------------------------------===// Index: cfe/trunk/lib/Serialization/CMakeLists.txt =================================================================== --- cfe/trunk/lib/Serialization/CMakeLists.txt +++ cfe/trunk/lib/Serialization/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS BitReader + BitstreamReader Support ) Index: cfe/trunk/lib/Serialization/GeneratePCH.cpp =================================================================== --- cfe/trunk/lib/Serialization/GeneratePCH.cpp +++ cfe/trunk/lib/Serialization/GeneratePCH.cpp @@ -16,7 +16,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTWriter.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" using namespace clang; Index: cfe/trunk/lib/Serialization/GlobalModuleIndex.cpp =================================================================== --- cfe/trunk/lib/Serialization/GlobalModuleIndex.cpp +++ cfe/trunk/lib/Serialization/GlobalModuleIndex.cpp @@ -21,8 +21,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/DJB.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/LockFileManager.h" Index: cfe/trunk/lib/Serialization/PCHContainerOperations.cpp =================================================================== --- cfe/trunk/lib/Serialization/PCHContainerOperations.cpp +++ cfe/trunk/lib/Serialization/PCHContainerOperations.cpp @@ -13,7 +13,7 @@ #include "clang/Serialization/PCHContainerOperations.h" #include "clang/AST/ASTConsumer.h" #include "clang/Lex/ModuleLoader.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/raw_ostream.h" #include Index: cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp =================================================================== --- cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp +++ cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp @@ -20,7 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; Index: cfe/trunk/unittests/Serialization/CMakeLists.txt =================================================================== --- cfe/trunk/unittests/Serialization/CMakeLists.txt +++ cfe/trunk/unittests/Serialization/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS BitReader + BitstreamReader Support ) Index: clang-tools-extra/trunk/clang-doc/BitcodeReader.h =================================================================== --- clang-tools-extra/trunk/clang-doc/BitcodeReader.h +++ clang-tools-extra/trunk/clang-doc/BitcodeReader.h @@ -20,7 +20,7 @@ #include "clang/AST/AST.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Error.h" namespace clang { Index: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h =================================================================== --- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h +++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h @@ -20,7 +20,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include #include Index: clang-tools-extra/trunk/clang-doc/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-doc/CMakeLists.txt +++ clang-tools-extra/trunk/clang-doc/CMakeLists.txt @@ -1,7 +1,6 @@ set(LLVM_LINK_COMPONENTS support - BitReader - BitWriter + BitstreamReader ) add_clang_library(clangDoc Index: clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp @@ -10,8 +10,8 @@ #include "BitcodeWriter.h" #include "ClangDocTest.h" #include "Representation.h" -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "gtest/gtest.h" namespace clang { Index: clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt +++ clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt @@ -1,7 +1,6 @@ set(LLVM_LINK_COMPONENTS support - BitReader - BitWriter + BitstreamReader ) get_filename_component(CLANG_DOC_SOURCE_DIR Index: llvm/trunk/include/llvm/Bitcode/BitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/BitCodes.h +++ llvm/trunk/include/llvm/Bitcode/BitCodes.h @@ -1,182 +0,0 @@ -//===- BitCodes.h - Enum values for the bitcode format ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This header Bitcode enum values. -// -// The enum values defined in this file should be considered permanent. If -// new features are added, they should have values added at the end of the -// respective lists. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_BITCODE_BITCODES_H -#define LLVM_BITCODE_BITCODES_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/ErrorHandling.h" -#include - -namespace llvm { -/// Offsets of the 32-bit fields of bitcode wrapper header. -static const unsigned BWH_MagicField = 0 * 4; -static const unsigned BWH_VersionField = 1 * 4; -static const unsigned BWH_OffsetField = 2 * 4; -static const unsigned BWH_SizeField = 3 * 4; -static const unsigned BWH_CPUTypeField = 4 * 4; -static const unsigned BWH_HeaderSize = 5 * 4; - -namespace bitc { - enum StandardWidths { - BlockIDWidth = 8, // We use VBR-8 for block IDs. - CodeLenWidth = 4, // Codelen are VBR-4. - BlockSizeWidth = 32 // BlockSize up to 2^32 32-bit words = 16GB per block. - }; - - // The standard abbrev namespace always has a way to exit a block, enter a - // nested block, define abbrevs, and define an unabbreviated record. - enum FixedAbbrevIDs { - END_BLOCK = 0, // Must be zero to guarantee termination for broken bitcode. - ENTER_SUBBLOCK = 1, - - /// DEFINE_ABBREV - Defines an abbrev for the current block. It consists - /// of a vbr5 for # operand infos. Each operand info is emitted with a - /// single bit to indicate if it is a literal encoding. If so, the value is - /// emitted with a vbr8. If not, the encoding is emitted as 3 bits followed - /// by the info value as a vbr5 if needed. - DEFINE_ABBREV = 2, - - // UNABBREV_RECORDs are emitted with a vbr6 for the record code, followed by - // a vbr6 for the # operands, followed by vbr6's for each operand. - UNABBREV_RECORD = 3, - - // This is not a code, this is a marker for the first abbrev assignment. - FIRST_APPLICATION_ABBREV = 4 - }; - - /// StandardBlockIDs - All bitcode files can optionally include a BLOCKINFO - /// block, which contains metadata about other blocks in the file. - enum StandardBlockIDs { - /// BLOCKINFO_BLOCK is used to define metadata about blocks, for example, - /// standard abbrevs that should be available to all blocks of a specified - /// ID. - BLOCKINFO_BLOCK_ID = 0, - - // Block IDs 1-7 are reserved for future expansion. - FIRST_APPLICATION_BLOCKID = 8 - }; - - /// BlockInfoCodes - The blockinfo block contains metadata about user-defined - /// blocks. - enum BlockInfoCodes { - // DEFINE_ABBREV has magic semantics here, applying to the current SETBID'd - // block, instead of the BlockInfo block. - - BLOCKINFO_CODE_SETBID = 1, // SETBID: [blockid#] - BLOCKINFO_CODE_BLOCKNAME = 2, // BLOCKNAME: [name] - BLOCKINFO_CODE_SETRECORDNAME = 3 // BLOCKINFO_CODE_SETRECORDNAME: - // [id, name] - }; - -} // End bitc namespace - -/// BitCodeAbbrevOp - This describes one or more operands in an abbreviation. -/// This is actually a union of two different things: -/// 1. It could be a literal integer value ("the operand is always 17"). -/// 2. It could be an encoding specification ("this operand encoded like so"). -/// -class BitCodeAbbrevOp { - uint64_t Val; // A literal value or data for an encoding. - bool IsLiteral : 1; // Indicate whether this is a literal value or not. - unsigned Enc : 3; // The encoding to use. -public: - enum Encoding { - Fixed = 1, // A fixed width field, Val specifies number of bits. - VBR = 2, // A VBR field where Val specifies the width of each chunk. - Array = 3, // A sequence of fields, next field species elt encoding. - Char6 = 4, // A 6-bit fixed field which maps to [a-zA-Z0-9._]. - Blob = 5 // 32-bit aligned array of 8-bit characters. - }; - - explicit BitCodeAbbrevOp(uint64_t V) : Val(V), IsLiteral(true) {} - explicit BitCodeAbbrevOp(Encoding E, uint64_t Data = 0) - : Val(Data), IsLiteral(false), Enc(E) {} - - bool isLiteral() const { return IsLiteral; } - bool isEncoding() const { return !IsLiteral; } - - // Accessors for literals. - uint64_t getLiteralValue() const { assert(isLiteral()); return Val; } - - // Accessors for encoding info. - Encoding getEncoding() const { assert(isEncoding()); return (Encoding)Enc; } - uint64_t getEncodingData() const { - assert(isEncoding() && hasEncodingData()); - return Val; - } - - bool hasEncodingData() const { return hasEncodingData(getEncoding()); } - static bool hasEncodingData(Encoding E) { - switch (E) { - case Fixed: - case VBR: - return true; - case Array: - case Char6: - case Blob: - return false; - } - report_fatal_error("Invalid encoding"); - } - - /// isChar6 - Return true if this character is legal in the Char6 encoding. - static bool isChar6(char C) { - if (C >= 'a' && C <= 'z') return true; - if (C >= 'A' && C <= 'Z') return true; - if (C >= '0' && C <= '9') return true; - if (C == '.' || C == '_') return true; - return false; - } - static unsigned EncodeChar6(char C) { - if (C >= 'a' && C <= 'z') return C-'a'; - if (C >= 'A' && C <= 'Z') return C-'A'+26; - if (C >= '0' && C <= '9') return C-'0'+26+26; - if (C == '.') return 62; - if (C == '_') return 63; - llvm_unreachable("Not a value Char6 character!"); - } - - static char DecodeChar6(unsigned V) { - assert((V & ~63) == 0 && "Not a Char6 encoded character!"); - return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._" - [V]; - } - -}; - -/// BitCodeAbbrev - This class represents an abbreviation record. An -/// abbreviation allows a complex record that has redundancy to be stored in a -/// specialized format instead of the fully-general, fully-vbr, format. -class BitCodeAbbrev { - SmallVector OperandList; - -public: - unsigned getNumOperandInfos() const { - return static_cast(OperandList.size()); - } - const BitCodeAbbrevOp &getOperandInfo(unsigned N) const { - return OperandList[N]; - } - - void Add(const BitCodeAbbrevOp &OpInfo) { - OperandList.push_back(OpInfo); - } -}; -} // End llvm namespace - -#endif Index: llvm/trunk/include/llvm/Bitcode/BitcodeReader.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/BitcodeReader.h +++ llvm/trunk/include/llvm/Bitcode/BitcodeReader.h @@ -15,7 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitstream/BitCodes.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" Index: llvm/trunk/include/llvm/Bitcode/BitstreamReader.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/BitstreamReader.h +++ llvm/trunk/include/llvm/Bitcode/BitstreamReader.h @@ -1,553 +0,0 @@ -//===- BitstreamReader.h - Low-level bitstream reader interface -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This header defines the BitstreamReader class. This class can be used to -// read an arbitrary bitstream, regardless of its contents. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_BITCODE_BITSTREAMREADER_H -#define LLVM_BITCODE_BITSTREAMREADER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace llvm { - -/// This class maintains the abbreviations read from a block info block. -class BitstreamBlockInfo { -public: - /// This contains information emitted to BLOCKINFO_BLOCK blocks. These - /// describe abbreviations that all blocks of the specified ID inherit. - struct BlockInfo { - unsigned BlockID; - std::vector> Abbrevs; - std::string Name; - std::vector> RecordNames; - }; - -private: - std::vector BlockInfoRecords; - -public: - /// If there is block info for the specified ID, return it, otherwise return - /// null. - const BlockInfo *getBlockInfo(unsigned BlockID) const { - // Common case, the most recent entry matches BlockID. - if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID) - return &BlockInfoRecords.back(); - - for (unsigned i = 0, e = static_cast(BlockInfoRecords.size()); - i != e; ++i) - if (BlockInfoRecords[i].BlockID == BlockID) - return &BlockInfoRecords[i]; - return nullptr; - } - - BlockInfo &getOrCreateBlockInfo(unsigned BlockID) { - if (const BlockInfo *BI = getBlockInfo(BlockID)) - return *const_cast(BI); - - // Otherwise, add a new record. - BlockInfoRecords.emplace_back(); - BlockInfoRecords.back().BlockID = BlockID; - return BlockInfoRecords.back(); - } -}; - -/// This represents a position within a bitstream. There may be multiple -/// independent cursors reading within one bitstream, each maintaining their -/// own local state. -class SimpleBitstreamCursor { - ArrayRef BitcodeBytes; - size_t NextChar = 0; - -public: - /// This is the current data we have pulled from the stream but have not - /// returned to the client. This is specifically and intentionally defined to - /// follow the word size of the host machine for efficiency. We use word_t in - /// places that are aware of this to make it perfectly explicit what is going - /// on. - using word_t = size_t; - -private: - word_t CurWord = 0; - - /// This is the number of bits in CurWord that are valid. This is always from - /// [0...bits_of(size_t)-1] inclusive. - unsigned BitsInCurWord = 0; - -public: - static const constexpr size_t MaxChunkSize = sizeof(word_t) * 8; - - SimpleBitstreamCursor() = default; - explicit SimpleBitstreamCursor(ArrayRef BitcodeBytes) - : BitcodeBytes(BitcodeBytes) {} - explicit SimpleBitstreamCursor(StringRef BitcodeBytes) - : BitcodeBytes(arrayRefFromStringRef(BitcodeBytes)) {} - explicit SimpleBitstreamCursor(MemoryBufferRef BitcodeBytes) - : SimpleBitstreamCursor(BitcodeBytes.getBuffer()) {} - - bool canSkipToPos(size_t pos) const { - // pos can be skipped to if it is a valid address or one byte past the end. - return pos <= BitcodeBytes.size(); - } - - bool AtEndOfStream() { - return BitsInCurWord == 0 && BitcodeBytes.size() <= NextChar; - } - - /// Return the bit # of the bit we are reading. - uint64_t GetCurrentBitNo() const { - return NextChar*CHAR_BIT - BitsInCurWord; - } - - // Return the byte # of the current bit. - uint64_t getCurrentByteNo() const { return GetCurrentBitNo() / 8; } - - ArrayRef getBitcodeBytes() const { return BitcodeBytes; } - - /// Reset the stream to the specified bit number. - Error JumpToBit(uint64_t BitNo) { - size_t ByteNo = size_t(BitNo/8) & ~(sizeof(word_t)-1); - unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1)); - assert(canSkipToPos(ByteNo) && "Invalid location"); - - // Move the cursor to the right word. - NextChar = ByteNo; - BitsInCurWord = 0; - - // Skip over any bits that are already consumed. - if (WordBitNo) { - if (Expected Res = Read(WordBitNo)) - return Error::success(); - else - return Res.takeError(); - } - - return Error::success(); - } - - /// Get a pointer into the bitstream at the specified byte offset. - const uint8_t *getPointerToByte(uint64_t ByteNo, uint64_t NumBytes) { - return BitcodeBytes.data() + ByteNo; - } - - /// Get a pointer into the bitstream at the specified bit offset. - /// - /// The bit offset must be on a byte boundary. - const uint8_t *getPointerToBit(uint64_t BitNo, uint64_t NumBytes) { - assert(!(BitNo % 8) && "Expected bit on byte boundary"); - return getPointerToByte(BitNo / 8, NumBytes); - } - - Error fillCurWord() { - if (NextChar >= BitcodeBytes.size()) - return createStringError(std::errc::io_error, - "Unexpected end of file reading %u of %u bytes", - NextChar, BitcodeBytes.size()); - - // Read the next word from the stream. - const uint8_t *NextCharPtr = BitcodeBytes.data() + NextChar; - unsigned BytesRead; - if (BitcodeBytes.size() >= NextChar + sizeof(word_t)) { - BytesRead = sizeof(word_t); - CurWord = - support::endian::read( - NextCharPtr); - } else { - // Short read. - BytesRead = BitcodeBytes.size() - NextChar; - CurWord = 0; - for (unsigned B = 0; B != BytesRead; ++B) - CurWord |= uint64_t(NextCharPtr[B]) << (B * 8); - } - NextChar += BytesRead; - BitsInCurWord = BytesRead * 8; - return Error::success(); - } - - Expected Read(unsigned NumBits) { - static const unsigned BitsInWord = MaxChunkSize; - - assert(NumBits && NumBits <= BitsInWord && - "Cannot return zero or more than BitsInWord bits!"); - - static const unsigned Mask = sizeof(word_t) > 4 ? 0x3f : 0x1f; - - // If the field is fully contained by CurWord, return it quickly. - if (BitsInCurWord >= NumBits) { - word_t R = CurWord & (~word_t(0) >> (BitsInWord - NumBits)); - - // Use a mask to avoid undefined behavior. - CurWord >>= (NumBits & Mask); - - BitsInCurWord -= NumBits; - return R; - } - - word_t R = BitsInCurWord ? CurWord : 0; - unsigned BitsLeft = NumBits - BitsInCurWord; - - if (Error fillResult = fillCurWord()) - return std::move(fillResult); - - // If we run out of data, abort. - if (BitsLeft > BitsInCurWord) - return createStringError(std::errc::io_error, - "Unexpected end of file reading %u of %u bits", - BitsInCurWord, BitsLeft); - - word_t R2 = CurWord & (~word_t(0) >> (BitsInWord - BitsLeft)); - - // Use a mask to avoid undefined behavior. - CurWord >>= (BitsLeft & Mask); - - BitsInCurWord -= BitsLeft; - - R |= R2 << (NumBits - BitsLeft); - - return R; - } - - Expected ReadVBR(unsigned NumBits) { - Expected MaybeRead = Read(NumBits); - if (!MaybeRead) - return MaybeRead; - uint32_t Piece = MaybeRead.get(); - - if ((Piece & (1U << (NumBits-1))) == 0) - return Piece; - - uint32_t Result = 0; - unsigned NextBit = 0; - while (true) { - Result |= (Piece & ((1U << (NumBits-1))-1)) << NextBit; - - if ((Piece & (1U << (NumBits-1))) == 0) - return Result; - - NextBit += NumBits-1; - MaybeRead = Read(NumBits); - if (!MaybeRead) - return MaybeRead; - Piece = MaybeRead.get(); - } - } - - // Read a VBR that may have a value up to 64-bits in size. The chunk size of - // the VBR must still be <= 32 bits though. - Expected ReadVBR64(unsigned NumBits) { - Expected MaybeRead = Read(NumBits); - if (!MaybeRead) - return MaybeRead; - uint32_t Piece = MaybeRead.get(); - - if ((Piece & (1U << (NumBits-1))) == 0) - return uint64_t(Piece); - - uint64_t Result = 0; - unsigned NextBit = 0; - while (true) { - Result |= uint64_t(Piece & ((1U << (NumBits-1))-1)) << NextBit; - - if ((Piece & (1U << (NumBits-1))) == 0) - return Result; - - NextBit += NumBits-1; - MaybeRead = Read(NumBits); - if (!MaybeRead) - return MaybeRead; - Piece = MaybeRead.get(); - } - } - - void SkipToFourByteBoundary() { - // If word_t is 64-bits and if we've read less than 32 bits, just dump - // the bits we have up to the next 32-bit boundary. - if (sizeof(word_t) > 4 && - BitsInCurWord >= 32) { - CurWord >>= BitsInCurWord-32; - BitsInCurWord = 32; - return; - } - - BitsInCurWord = 0; - } - - /// Skip to the end of the file. - void skipToEnd() { NextChar = BitcodeBytes.size(); } -}; - -/// When advancing through a bitstream cursor, each advance can discover a few -/// different kinds of entries: -struct BitstreamEntry { - enum { - 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. - } 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; - } -}; - -/// This represents a position within a bitcode file, implemented on top of a -/// SimpleBitstreamCursor. -/// -/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not -/// be passed by value. -class BitstreamCursor : SimpleBitstreamCursor { - // This is the declared size of code values used for the current block, in - // bits. - unsigned CurCodeSize = 2; - - /// Abbrevs installed at in this block. - std::vector> CurAbbrevs; - - struct Block { - unsigned PrevCodeSize; - std::vector> PrevAbbrevs; - - explicit Block(unsigned PCS) : PrevCodeSize(PCS) {} - }; - - /// This tracks the codesize of parent blocks. - SmallVector BlockScope; - - BitstreamBlockInfo *BlockInfo = nullptr; - -public: - static const size_t MaxChunkSize = sizeof(word_t) * 8; - - BitstreamCursor() = default; - explicit BitstreamCursor(ArrayRef BitcodeBytes) - : SimpleBitstreamCursor(BitcodeBytes) {} - explicit BitstreamCursor(StringRef BitcodeBytes) - : SimpleBitstreamCursor(BitcodeBytes) {} - explicit BitstreamCursor(MemoryBufferRef BitcodeBytes) - : SimpleBitstreamCursor(BitcodeBytes) {} - - using SimpleBitstreamCursor::canSkipToPos; - using SimpleBitstreamCursor::AtEndOfStream; - using SimpleBitstreamCursor::getBitcodeBytes; - using SimpleBitstreamCursor::GetCurrentBitNo; - using SimpleBitstreamCursor::getCurrentByteNo; - using SimpleBitstreamCursor::getPointerToByte; - using SimpleBitstreamCursor::JumpToBit; - using SimpleBitstreamCursor::fillCurWord; - using SimpleBitstreamCursor::Read; - using SimpleBitstreamCursor::ReadVBR; - using SimpleBitstreamCursor::ReadVBR64; - - /// Return the number of bits used to encode an abbrev #. - unsigned getAbbrevIDWidth() const { return CurCodeSize; } - - /// Flags that modify the behavior of advance(). - enum { - /// If this flag is used, the advance() method does not automatically pop - /// the block scope when the end of a block is reached. - AF_DontPopBlockAtEnd = 1, - - /// If this flag is used, abbrev entries are returned just like normal - /// records. - AF_DontAutoprocessAbbrevs = 2 - }; - - /// Advance the current bitstream, returning the next entry in the stream. - Expected advance(unsigned Flags = 0) { - while (true) { - if (AtEndOfStream()) - return BitstreamEntry::getError(); - - Expected MaybeCode = ReadCode(); - if (!MaybeCode) - return MaybeCode.takeError(); - unsigned Code = MaybeCode.get(); - - if (Code == bitc::END_BLOCK) { - // Pop the end of the block unless Flags tells us not to. - if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd()) - return BitstreamEntry::getError(); - return BitstreamEntry::getEndBlock(); - } - - if (Code == bitc::ENTER_SUBBLOCK) { - if (Expected MaybeSubBlock = ReadSubBlockID()) - return BitstreamEntry::getSubBlock(MaybeSubBlock.get()); - else - return MaybeSubBlock.takeError(); - } - - if (Code == bitc::DEFINE_ABBREV && - !(Flags & AF_DontAutoprocessAbbrevs)) { - // We read and accumulate abbrev's, the client can't do anything with - // them anyway. - if (Error Err = ReadAbbrevRecord()) - return std::move(Err); - continue; - } - - return BitstreamEntry::getRecord(Code); - } - } - - /// This is a convenience function for clients that don't expect any - /// subblocks. This just skips over them automatically. - Expected advanceSkippingSubblocks(unsigned Flags = 0) { - while (true) { - // If we found a normal entry, return it. - Expected MaybeEntry = advance(Flags); - if (!MaybeEntry) - return MaybeEntry; - BitstreamEntry Entry = MaybeEntry.get(); - - if (Entry.Kind != BitstreamEntry::SubBlock) - return Entry; - - // If we found a sub-block, just skip over it and check the next entry. - if (Error Err = SkipBlock()) - return std::move(Err); - } - } - - Expected ReadCode() { return Read(CurCodeSize); } - - // Block header: - // [ENTER_SUBBLOCK, blockid, newcodelen, , blocklen] - - /// Having read the ENTER_SUBBLOCK code, read the BlockID for the block. - Expected ReadSubBlockID() { return ReadVBR(bitc::BlockIDWidth); } - - /// Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body - /// of this block. - Error SkipBlock() { - // Read and ignore the codelen value. - if (Expected Res = ReadVBR(bitc::CodeLenWidth)) - ; // Since we are skipping this block, we don't care what code widths are - // used inside of it. - else - return Res.takeError(); - - SkipToFourByteBoundary(); - Expected MaybeNum = Read(bitc::BlockSizeWidth); - if (!MaybeNum) - return MaybeNum.takeError(); - size_t NumFourBytes = MaybeNum.get(); - - // Check that the block wasn't partially defined, and that the offset isn't - // bogus. - size_t SkipTo = GetCurrentBitNo() + NumFourBytes * 4 * 8; - if (AtEndOfStream()) - return createStringError(std::errc::illegal_byte_sequence, - "can't skip block: already at end of stream"); - if (!canSkipToPos(SkipTo / 8)) - return createStringError(std::errc::illegal_byte_sequence, - "can't skip to bit %zu from %" PRIu64, SkipTo, - GetCurrentBitNo()); - - if (Error Res = JumpToBit(SkipTo)) - return Res; - - return Error::success(); - } - - /// Having read the ENTER_SUBBLOCK abbrevid, and enter the block. - Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr); - - bool ReadBlockEnd() { - if (BlockScope.empty()) return true; - - // Block tail: - // [END_BLOCK, ] - SkipToFourByteBoundary(); - - popBlockScope(); - return false; - } - -private: - void popBlockScope() { - CurCodeSize = BlockScope.back().PrevCodeSize; - - CurAbbrevs = std::move(BlockScope.back().PrevAbbrevs); - BlockScope.pop_back(); - } - - //===--------------------------------------------------------------------===// - // Record Processing - //===--------------------------------------------------------------------===// - -public: - /// Return the abbreviation for the specified AbbrevId. - const BitCodeAbbrev *getAbbrev(unsigned AbbrevID) { - unsigned AbbrevNo = AbbrevID - bitc::FIRST_APPLICATION_ABBREV; - if (AbbrevNo >= CurAbbrevs.size()) - report_fatal_error("Invalid abbrev number"); - return CurAbbrevs[AbbrevNo].get(); - } - - /// Read the current record and discard it, returning the code for the record. - Expected skipRecord(unsigned AbbrevID); - - Expected readRecord(unsigned AbbrevID, - SmallVectorImpl &Vals, - StringRef *Blob = nullptr); - - //===--------------------------------------------------------------------===// - // Abbrev Processing - //===--------------------------------------------------------------------===// - Error ReadAbbrevRecord(); - - /// Read and return a block info block from the bitstream. If an error was - /// encountered, return None. - /// - /// \param ReadBlockInfoNames Whether to read block/record name information in - /// the BlockInfo block. Only llvm-bcanalyzer uses this. - Expected> - ReadBlockInfoBlock(bool ReadBlockInfoNames = false); - - /// Set the block info to be used by this BitstreamCursor to interpret - /// abbreviated records. - void setBlockInfo(BitstreamBlockInfo *BI) { BlockInfo = BI; } -}; - -} // end llvm namespace - -#endif // LLVM_BITCODE_BITSTREAMREADER_H Index: llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h +++ llvm/trunk/include/llvm/Bitcode/BitstreamWriter.h @@ -1,547 +0,0 @@ -//===- BitstreamWriter.h - Low-level bitstream writer interface -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This header defines the BitstreamWriter class. This class can be used to -// write an arbitrary bitstream, regardless of its contents. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_BITCODE_BITSTREAMWRITER_H -#define LLVM_BITCODE_BITSTREAMWRITER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Support/Endian.h" -#include - -namespace llvm { - -class BitstreamWriter { - SmallVectorImpl &Out; - - /// CurBit - Always between 0 and 31 inclusive, specifies the next bit to use. - unsigned CurBit; - - /// CurValue - The current value. Only bits < CurBit are valid. - uint32_t CurValue; - - /// CurCodeSize - This is the declared size of code values used for the - /// current block, in bits. - unsigned CurCodeSize; - - /// BlockInfoCurBID - When emitting a BLOCKINFO_BLOCK, this is the currently - /// selected BLOCK ID. - unsigned BlockInfoCurBID; - - /// CurAbbrevs - Abbrevs installed at in this block. - std::vector> CurAbbrevs; - - struct Block { - unsigned PrevCodeSize; - size_t StartSizeWord; - std::vector> PrevAbbrevs; - Block(unsigned PCS, size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {} - }; - - /// BlockScope - This tracks the current blocks that we have entered. - std::vector BlockScope; - - /// BlockInfo - This contains information emitted to BLOCKINFO_BLOCK blocks. - /// These describe abbreviations that all blocks of the specified ID inherit. - struct BlockInfo { - unsigned BlockID; - std::vector> Abbrevs; - }; - std::vector BlockInfoRecords; - - void WriteByte(unsigned char Value) { - Out.push_back(Value); - } - - void WriteWord(unsigned Value) { - Value = support::endian::byte_swap(Value); - Out.append(reinterpret_cast(&Value), - reinterpret_cast(&Value + 1)); - } - - size_t GetBufferOffset() const { return Out.size(); } - - size_t GetWordIndex() const { - size_t Offset = GetBufferOffset(); - assert((Offset & 3) == 0 && "Not 32-bit aligned"); - return Offset / 4; - } - -public: - explicit BitstreamWriter(SmallVectorImpl &O) - : Out(O), CurBit(0), CurValue(0), CurCodeSize(2) {} - - ~BitstreamWriter() { - assert(CurBit == 0 && "Unflushed data remaining"); - assert(BlockScope.empty() && CurAbbrevs.empty() && "Block imbalance"); - } - - /// Retrieve the current position in the stream, in bits. - uint64_t GetCurrentBitNo() const { return GetBufferOffset() * 8 + CurBit; } - - /// Retrieve the number of bits currently used to encode an abbrev ID. - unsigned GetAbbrevIDWidth() const { return CurCodeSize; } - - //===--------------------------------------------------------------------===// - // Basic Primitives for emitting bits to the stream. - //===--------------------------------------------------------------------===// - - /// Backpatch a 32-bit word in the output at the given bit offset - /// with the specified value. - void BackpatchWord(uint64_t BitNo, unsigned NewWord) { - using namespace llvm::support; - unsigned ByteNo = BitNo / 8; - assert((!endian::readAtBitAlignment( - &Out[ByteNo], BitNo & 7)) && - "Expected to be patching over 0-value placeholders"); - endian::writeAtBitAlignment( - &Out[ByteNo], NewWord, BitNo & 7); - } - - void BackpatchWord64(uint64_t BitNo, uint64_t Val) { - BackpatchWord(BitNo, (uint32_t)Val); - BackpatchWord(BitNo + 32, (uint32_t)(Val >> 32)); - } - - void Emit(uint32_t Val, unsigned NumBits) { - assert(NumBits && NumBits <= 32 && "Invalid value size!"); - assert((Val & ~(~0U >> (32-NumBits))) == 0 && "High bits set!"); - CurValue |= Val << CurBit; - if (CurBit + NumBits < 32) { - CurBit += NumBits; - return; - } - - // Add the current word. - WriteWord(CurValue); - - if (CurBit) - CurValue = Val >> (32-CurBit); - else - CurValue = 0; - CurBit = (CurBit+NumBits) & 31; - } - - void FlushToWord() { - if (CurBit) { - WriteWord(CurValue); - CurBit = 0; - CurValue = 0; - } - } - - void EmitVBR(uint32_t Val, unsigned NumBits) { - assert(NumBits <= 32 && "Too many bits to emit!"); - uint32_t Threshold = 1U << (NumBits-1); - - // Emit the bits with VBR encoding, NumBits-1 bits at a time. - while (Val >= Threshold) { - Emit((Val & ((1 << (NumBits-1))-1)) | (1 << (NumBits-1)), NumBits); - Val >>= NumBits-1; - } - - Emit(Val, NumBits); - } - - void EmitVBR64(uint64_t Val, unsigned NumBits) { - assert(NumBits <= 32 && "Too many bits to emit!"); - if ((uint32_t)Val == Val) - return EmitVBR((uint32_t)Val, NumBits); - - uint32_t Threshold = 1U << (NumBits-1); - - // Emit the bits with VBR encoding, NumBits-1 bits at a time. - while (Val >= Threshold) { - Emit(((uint32_t)Val & ((1 << (NumBits-1))-1)) | - (1 << (NumBits-1)), NumBits); - Val >>= NumBits-1; - } - - Emit((uint32_t)Val, NumBits); - } - - /// EmitCode - Emit the specified code. - void EmitCode(unsigned Val) { - Emit(Val, CurCodeSize); - } - - //===--------------------------------------------------------------------===// - // Block Manipulation - //===--------------------------------------------------------------------===// - - /// getBlockInfo - If there is block info for the specified ID, return it, - /// otherwise return null. - BlockInfo *getBlockInfo(unsigned BlockID) { - // Common case, the most recent entry matches BlockID. - if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID) - return &BlockInfoRecords.back(); - - for (unsigned i = 0, e = static_cast(BlockInfoRecords.size()); - i != e; ++i) - if (BlockInfoRecords[i].BlockID == BlockID) - return &BlockInfoRecords[i]; - return nullptr; - } - - void EnterSubblock(unsigned BlockID, unsigned CodeLen) { - // Block header: - // [ENTER_SUBBLOCK, blockid, newcodelen, , blocklen] - EmitCode(bitc::ENTER_SUBBLOCK); - EmitVBR(BlockID, bitc::BlockIDWidth); - EmitVBR(CodeLen, bitc::CodeLenWidth); - FlushToWord(); - - size_t BlockSizeWordIndex = GetWordIndex(); - unsigned OldCodeSize = CurCodeSize; - - // Emit a placeholder, which will be replaced when the block is popped. - Emit(0, bitc::BlockSizeWidth); - - CurCodeSize = CodeLen; - - // Push the outer block's abbrev set onto the stack, start out with an - // empty abbrev set. - BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex); - BlockScope.back().PrevAbbrevs.swap(CurAbbrevs); - - // If there is a blockinfo for this BlockID, add all the predefined abbrevs - // to the abbrev list. - if (BlockInfo *Info = getBlockInfo(BlockID)) { - CurAbbrevs.insert(CurAbbrevs.end(), Info->Abbrevs.begin(), - Info->Abbrevs.end()); - } - } - - void ExitBlock() { - assert(!BlockScope.empty() && "Block scope imbalance!"); - const Block &B = BlockScope.back(); - - // Block tail: - // [END_BLOCK, ] - EmitCode(bitc::END_BLOCK); - FlushToWord(); - - // Compute the size of the block, in words, not counting the size field. - size_t SizeInWords = GetWordIndex() - B.StartSizeWord - 1; - uint64_t BitNo = uint64_t(B.StartSizeWord) * 32; - - // Update the block size field in the header of this sub-block. - BackpatchWord(BitNo, SizeInWords); - - // Restore the inner block's code size and abbrev table. - CurCodeSize = B.PrevCodeSize; - CurAbbrevs = std::move(B.PrevAbbrevs); - BlockScope.pop_back(); - } - - //===--------------------------------------------------------------------===// - // Record Emission - //===--------------------------------------------------------------------===// - -private: - /// EmitAbbreviatedLiteral - Emit a literal value according to its abbrev - /// record. This is a no-op, since the abbrev specifies the literal to use. - template - void EmitAbbreviatedLiteral(const BitCodeAbbrevOp &Op, uintty V) { - assert(Op.isLiteral() && "Not a literal"); - // If the abbrev specifies the literal value to use, don't emit - // anything. - assert(V == Op.getLiteralValue() && - "Invalid abbrev for record!"); - } - - /// EmitAbbreviatedField - Emit a single scalar field value with the specified - /// encoding. - template - void EmitAbbreviatedField(const BitCodeAbbrevOp &Op, uintty V) { - assert(!Op.isLiteral() && "Literals should use EmitAbbreviatedLiteral!"); - - // Encode the value as we are commanded. - switch (Op.getEncoding()) { - default: llvm_unreachable("Unknown encoding!"); - case BitCodeAbbrevOp::Fixed: - if (Op.getEncodingData()) - Emit((unsigned)V, (unsigned)Op.getEncodingData()); - break; - case BitCodeAbbrevOp::VBR: - if (Op.getEncodingData()) - EmitVBR64(V, (unsigned)Op.getEncodingData()); - break; - case BitCodeAbbrevOp::Char6: - Emit(BitCodeAbbrevOp::EncodeChar6((char)V), 6); - break; - } - } - - /// EmitRecordWithAbbrevImpl - This is the core implementation of the record - /// emission code. If BlobData is non-null, then it specifies an array of - /// data that should be emitted as part of the Blob or Array operand that is - /// known to exist at the end of the record. If Code is specified, then - /// it is the record code to emit before the Vals, which must not contain - /// the code. - template - void EmitRecordWithAbbrevImpl(unsigned Abbrev, ArrayRef Vals, - StringRef Blob, Optional Code) { - const char *BlobData = Blob.data(); - unsigned BlobLen = (unsigned) Blob.size(); - unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV; - assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!"); - const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get(); - - EmitCode(Abbrev); - - unsigned i = 0, e = static_cast(Abbv->getNumOperandInfos()); - if (Code) { - assert(e && "Expected non-empty abbreviation"); - const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i++); - - if (Op.isLiteral()) - EmitAbbreviatedLiteral(Op, Code.getValue()); - else { - assert(Op.getEncoding() != BitCodeAbbrevOp::Array && - Op.getEncoding() != BitCodeAbbrevOp::Blob && - "Expected literal or scalar"); - EmitAbbreviatedField(Op, Code.getValue()); - } - } - - unsigned RecordIdx = 0; - for (; i != e; ++i) { - const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); - if (Op.isLiteral()) { - assert(RecordIdx < Vals.size() && "Invalid abbrev/record"); - EmitAbbreviatedLiteral(Op, Vals[RecordIdx]); - ++RecordIdx; - } else if (Op.getEncoding() == BitCodeAbbrevOp::Array) { - // Array case. - assert(i + 2 == e && "array op not second to last?"); - const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); - - // If this record has blob data, emit it, otherwise we must have record - // entries to encode this way. - if (BlobData) { - assert(RecordIdx == Vals.size() && - "Blob data and record entries specified for array!"); - // Emit a vbr6 to indicate the number of elements present. - EmitVBR(static_cast(BlobLen), 6); - - // Emit each field. - for (unsigned i = 0; i != BlobLen; ++i) - EmitAbbreviatedField(EltEnc, (unsigned char)BlobData[i]); - - // Know that blob data is consumed for assertion below. - BlobData = nullptr; - } else { - // Emit a vbr6 to indicate the number of elements present. - EmitVBR(static_cast(Vals.size()-RecordIdx), 6); - - // Emit each field. - for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx) - EmitAbbreviatedField(EltEnc, Vals[RecordIdx]); - } - } else if (Op.getEncoding() == BitCodeAbbrevOp::Blob) { - // If this record has blob data, emit it, otherwise we must have record - // entries to encode this way. - - if (BlobData) { - assert(RecordIdx == Vals.size() && - "Blob data and record entries specified for blob operand!"); - - assert(Blob.data() == BlobData && "BlobData got moved"); - assert(Blob.size() == BlobLen && "BlobLen got changed"); - emitBlob(Blob); - BlobData = nullptr; - } else { - emitBlob(Vals.slice(RecordIdx)); - } - } else { // Single scalar field. - assert(RecordIdx < Vals.size() && "Invalid abbrev/record"); - EmitAbbreviatedField(Op, Vals[RecordIdx]); - ++RecordIdx; - } - } - assert(RecordIdx == Vals.size() && "Not all record operands emitted!"); - assert(BlobData == nullptr && - "Blob data specified for record that doesn't use it!"); - } - -public: - /// Emit a blob, including flushing before and tail-padding. - template - void emitBlob(ArrayRef Bytes, bool ShouldEmitSize = true) { - // Emit a vbr6 to indicate the number of elements present. - if (ShouldEmitSize) - EmitVBR(static_cast(Bytes.size()), 6); - - // Flush to a 32-bit alignment boundary. - FlushToWord(); - - // Emit literal bytes. - for (const auto &B : Bytes) { - assert(isUInt<8>(B) && "Value too large to emit as byte"); - WriteByte((unsigned char)B); - } - - // Align end to 32-bits. - while (GetBufferOffset() & 3) - WriteByte(0); - } - void emitBlob(StringRef Bytes, bool ShouldEmitSize = true) { - emitBlob(makeArrayRef((const uint8_t *)Bytes.data(), Bytes.size()), - ShouldEmitSize); - } - - /// EmitRecord - Emit the specified record to the stream, using an abbrev if - /// we have one to compress the output. - template - void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev = 0) { - if (!Abbrev) { - // If we don't have an abbrev to use, emit this in its fully unabbreviated - // form. - auto Count = static_cast(makeArrayRef(Vals).size()); - EmitCode(bitc::UNABBREV_RECORD); - EmitVBR(Code, 6); - EmitVBR(Count, 6); - for (unsigned i = 0, e = Count; i != e; ++i) - EmitVBR64(Vals[i], 6); - return; - } - - EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), StringRef(), Code); - } - - /// EmitRecordWithAbbrev - Emit a record with the specified abbreviation. - /// Unlike EmitRecord, the code for the record should be included in Vals as - /// the first entry. - template - void EmitRecordWithAbbrev(unsigned Abbrev, const Container &Vals) { - EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), StringRef(), None); - } - - /// EmitRecordWithBlob - Emit the specified record to the stream, using an - /// abbrev that includes a blob at the end. The blob data to emit is - /// specified by the pointer and length specified at the end. In contrast to - /// EmitRecord, this routine expects that the first entry in Vals is the code - /// of the record. - template - void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, - StringRef Blob) { - EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), Blob, None); - } - template - void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, - const char *BlobData, unsigned BlobLen) { - return EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), - StringRef(BlobData, BlobLen), None); - } - - /// EmitRecordWithArray - Just like EmitRecordWithBlob, works with records - /// that end with an array. - template - void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, - StringRef Array) { - EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), Array, None); - } - template - void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, - const char *ArrayData, unsigned ArrayLen) { - return EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), - StringRef(ArrayData, ArrayLen), None); - } - - //===--------------------------------------------------------------------===// - // Abbrev Emission - //===--------------------------------------------------------------------===// - -private: - // Emit the abbreviation as a DEFINE_ABBREV record. - void EncodeAbbrev(const BitCodeAbbrev &Abbv) { - EmitCode(bitc::DEFINE_ABBREV); - EmitVBR(Abbv.getNumOperandInfos(), 5); - for (unsigned i = 0, e = static_cast(Abbv.getNumOperandInfos()); - i != e; ++i) { - const BitCodeAbbrevOp &Op = Abbv.getOperandInfo(i); - Emit(Op.isLiteral(), 1); - if (Op.isLiteral()) { - EmitVBR64(Op.getLiteralValue(), 8); - } else { - Emit(Op.getEncoding(), 3); - if (Op.hasEncodingData()) - EmitVBR64(Op.getEncodingData(), 5); - } - } - } -public: - - /// Emits the abbreviation \p Abbv to the stream. - unsigned EmitAbbrev(std::shared_ptr Abbv) { - EncodeAbbrev(*Abbv); - CurAbbrevs.push_back(std::move(Abbv)); - return static_cast(CurAbbrevs.size())-1 + - bitc::FIRST_APPLICATION_ABBREV; - } - - //===--------------------------------------------------------------------===// - // BlockInfo Block Emission - //===--------------------------------------------------------------------===// - - /// EnterBlockInfoBlock - Start emitting the BLOCKINFO_BLOCK. - void EnterBlockInfoBlock() { - EnterSubblock(bitc::BLOCKINFO_BLOCK_ID, 2); - BlockInfoCurBID = ~0U; - BlockInfoRecords.clear(); - } -private: - /// SwitchToBlockID - If we aren't already talking about the specified block - /// ID, emit a BLOCKINFO_CODE_SETBID record. - void SwitchToBlockID(unsigned BlockID) { - if (BlockInfoCurBID == BlockID) return; - SmallVector V; - V.push_back(BlockID); - EmitRecord(bitc::BLOCKINFO_CODE_SETBID, V); - BlockInfoCurBID = BlockID; - } - - BlockInfo &getOrCreateBlockInfo(unsigned BlockID) { - if (BlockInfo *BI = getBlockInfo(BlockID)) - return *BI; - - // Otherwise, add a new record. - BlockInfoRecords.emplace_back(); - BlockInfoRecords.back().BlockID = BlockID; - return BlockInfoRecords.back(); - } - -public: - - /// EmitBlockInfoAbbrev - Emit a DEFINE_ABBREV record for the specified - /// BlockID. - unsigned EmitBlockInfoAbbrev(unsigned BlockID, std::shared_ptr Abbv) { - SwitchToBlockID(BlockID); - EncodeAbbrev(*Abbv); - - // Add the abbrev to the specified block record. - BlockInfo &Info = getOrCreateBlockInfo(BlockID); - Info.Abbrevs.push_back(std::move(Abbv)); - - return Info.Abbrevs.size()-1+bitc::FIRST_APPLICATION_ABBREV; - } -}; - - -} // End llvm namespace - -#endif Index: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h @@ -17,7 +17,7 @@ #ifndef LLVM_BITCODE_LLVMBITCODES_H #define LLVM_BITCODE_LLVMBITCODES_H -#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitstream/BitCodes.h" namespace llvm { namespace bitc { Index: llvm/trunk/include/llvm/Bitstream/BitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitstream/BitCodes.h +++ llvm/trunk/include/llvm/Bitstream/BitCodes.h @@ -0,0 +1,182 @@ +//===- BitCodes.h - Enum values for the bitstream format --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header defines bitstream enum values. +// +// The enum values defined in this file should be considered permanent. If +// new features are added, they should have values added at the end of the +// respective lists. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BITSTREAM_BITCODES_H +#define LLVM_BITSTREAM_BITCODES_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace llvm { +/// Offsets of the 32-bit fields of bitstream wrapper header. +static const unsigned BWH_MagicField = 0 * 4; +static const unsigned BWH_VersionField = 1 * 4; +static const unsigned BWH_OffsetField = 2 * 4; +static const unsigned BWH_SizeField = 3 * 4; +static const unsigned BWH_CPUTypeField = 4 * 4; +static const unsigned BWH_HeaderSize = 5 * 4; + +namespace bitc { + enum StandardWidths { + BlockIDWidth = 8, // We use VBR-8 for block IDs. + CodeLenWidth = 4, // Codelen are VBR-4. + BlockSizeWidth = 32 // BlockSize up to 2^32 32-bit words = 16GB per block. + }; + + // The standard abbrev namespace always has a way to exit a block, enter a + // nested block, define abbrevs, and define an unabbreviated record. + enum FixedAbbrevIDs { + END_BLOCK = 0, // Must be zero to guarantee termination for broken bitcode. + ENTER_SUBBLOCK = 1, + + /// DEFINE_ABBREV - Defines an abbrev for the current block. It consists + /// of a vbr5 for # operand infos. Each operand info is emitted with a + /// single bit to indicate if it is a literal encoding. If so, the value is + /// emitted with a vbr8. If not, the encoding is emitted as 3 bits followed + /// by the info value as a vbr5 if needed. + DEFINE_ABBREV = 2, + + // UNABBREV_RECORDs are emitted with a vbr6 for the record code, followed by + // a vbr6 for the # operands, followed by vbr6's for each operand. + UNABBREV_RECORD = 3, + + // This is not a code, this is a marker for the first abbrev assignment. + FIRST_APPLICATION_ABBREV = 4 + }; + + /// StandardBlockIDs - All bitcode files can optionally include a BLOCKINFO + /// block, which contains metadata about other blocks in the file. + enum StandardBlockIDs { + /// BLOCKINFO_BLOCK is used to define metadata about blocks, for example, + /// standard abbrevs that should be available to all blocks of a specified + /// ID. + BLOCKINFO_BLOCK_ID = 0, + + // Block IDs 1-7 are reserved for future expansion. + FIRST_APPLICATION_BLOCKID = 8 + }; + + /// BlockInfoCodes - The blockinfo block contains metadata about user-defined + /// blocks. + enum BlockInfoCodes { + // DEFINE_ABBREV has magic semantics here, applying to the current SETBID'd + // block, instead of the BlockInfo block. + + BLOCKINFO_CODE_SETBID = 1, // SETBID: [blockid#] + BLOCKINFO_CODE_BLOCKNAME = 2, // BLOCKNAME: [name] + BLOCKINFO_CODE_SETRECORDNAME = 3 // BLOCKINFO_CODE_SETRECORDNAME: + // [id, name] + }; + +} // End bitc namespace + +/// BitCodeAbbrevOp - This describes one or more operands in an abbreviation. +/// This is actually a union of two different things: +/// 1. It could be a literal integer value ("the operand is always 17"). +/// 2. It could be an encoding specification ("this operand encoded like so"). +/// +class BitCodeAbbrevOp { + uint64_t Val; // A literal value or data for an encoding. + bool IsLiteral : 1; // Indicate whether this is a literal value or not. + unsigned Enc : 3; // The encoding to use. +public: + enum Encoding { + Fixed = 1, // A fixed width field, Val specifies number of bits. + VBR = 2, // A VBR field where Val specifies the width of each chunk. + Array = 3, // A sequence of fields, next field species elt encoding. + Char6 = 4, // A 6-bit fixed field which maps to [a-zA-Z0-9._]. + Blob = 5 // 32-bit aligned array of 8-bit characters. + }; + + explicit BitCodeAbbrevOp(uint64_t V) : Val(V), IsLiteral(true) {} + explicit BitCodeAbbrevOp(Encoding E, uint64_t Data = 0) + : Val(Data), IsLiteral(false), Enc(E) {} + + bool isLiteral() const { return IsLiteral; } + bool isEncoding() const { return !IsLiteral; } + + // Accessors for literals. + uint64_t getLiteralValue() const { assert(isLiteral()); return Val; } + + // Accessors for encoding info. + Encoding getEncoding() const { assert(isEncoding()); return (Encoding)Enc; } + uint64_t getEncodingData() const { + assert(isEncoding() && hasEncodingData()); + return Val; + } + + bool hasEncodingData() const { return hasEncodingData(getEncoding()); } + static bool hasEncodingData(Encoding E) { + switch (E) { + case Fixed: + case VBR: + return true; + case Array: + case Char6: + case Blob: + return false; + } + report_fatal_error("Invalid encoding"); + } + + /// isChar6 - Return true if this character is legal in the Char6 encoding. + static bool isChar6(char C) { + if (C >= 'a' && C <= 'z') return true; + if (C >= 'A' && C <= 'Z') return true; + if (C >= '0' && C <= '9') return true; + if (C == '.' || C == '_') return true; + return false; + } + static unsigned EncodeChar6(char C) { + if (C >= 'a' && C <= 'z') return C-'a'; + if (C >= 'A' && C <= 'Z') return C-'A'+26; + if (C >= '0' && C <= '9') return C-'0'+26+26; + if (C == '.') return 62; + if (C == '_') return 63; + llvm_unreachable("Not a value Char6 character!"); + } + + static char DecodeChar6(unsigned V) { + assert((V & ~63) == 0 && "Not a Char6 encoded character!"); + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._" + [V]; + } + +}; + +/// BitCodeAbbrev - This class represents an abbreviation record. An +/// abbreviation allows a complex record that has redundancy to be stored in a +/// specialized format instead of the fully-general, fully-vbr, format. +class BitCodeAbbrev { + SmallVector OperandList; + +public: + unsigned getNumOperandInfos() const { + return static_cast(OperandList.size()); + } + const BitCodeAbbrevOp &getOperandInfo(unsigned N) const { + return OperandList[N]; + } + + void Add(const BitCodeAbbrevOp &OpInfo) { + OperandList.push_back(OpInfo); + } +}; +} // End llvm namespace + +#endif Index: llvm/trunk/include/llvm/Bitstream/BitstreamReader.h =================================================================== --- llvm/trunk/include/llvm/Bitstream/BitstreamReader.h +++ llvm/trunk/include/llvm/Bitstream/BitstreamReader.h @@ -0,0 +1,553 @@ +//===- BitstreamReader.h - Low-level bitstream reader interface -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitstreamReader class. This class can be used to +// read an arbitrary bitstream, regardless of its contents. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BITSTREAM_BITSTREAMREADER_H +#define LLVM_BITSTREAM_BITSTREAMREADER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + +/// This class maintains the abbreviations read from a block info block. +class BitstreamBlockInfo { +public: + /// This contains information emitted to BLOCKINFO_BLOCK blocks. These + /// describe abbreviations that all blocks of the specified ID inherit. + struct BlockInfo { + unsigned BlockID; + std::vector> Abbrevs; + std::string Name; + std::vector> RecordNames; + }; + +private: + std::vector BlockInfoRecords; + +public: + /// If there is block info for the specified ID, return it, otherwise return + /// null. + const BlockInfo *getBlockInfo(unsigned BlockID) const { + // Common case, the most recent entry matches BlockID. + if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID) + return &BlockInfoRecords.back(); + + for (unsigned i = 0, e = static_cast(BlockInfoRecords.size()); + i != e; ++i) + if (BlockInfoRecords[i].BlockID == BlockID) + return &BlockInfoRecords[i]; + return nullptr; + } + + BlockInfo &getOrCreateBlockInfo(unsigned BlockID) { + if (const BlockInfo *BI = getBlockInfo(BlockID)) + return *const_cast(BI); + + // Otherwise, add a new record. + BlockInfoRecords.emplace_back(); + BlockInfoRecords.back().BlockID = BlockID; + return BlockInfoRecords.back(); + } +}; + +/// This represents a position within a bitstream. There may be multiple +/// independent cursors reading within one bitstream, each maintaining their +/// own local state. +class SimpleBitstreamCursor { + ArrayRef BitcodeBytes; + size_t NextChar = 0; + +public: + /// This is the current data we have pulled from the stream but have not + /// returned to the client. This is specifically and intentionally defined to + /// follow the word size of the host machine for efficiency. We use word_t in + /// places that are aware of this to make it perfectly explicit what is going + /// on. + using word_t = size_t; + +private: + word_t CurWord = 0; + + /// This is the number of bits in CurWord that are valid. This is always from + /// [0...bits_of(size_t)-1] inclusive. + unsigned BitsInCurWord = 0; + +public: + static const constexpr size_t MaxChunkSize = sizeof(word_t) * 8; + + SimpleBitstreamCursor() = default; + explicit SimpleBitstreamCursor(ArrayRef BitcodeBytes) + : BitcodeBytes(BitcodeBytes) {} + explicit SimpleBitstreamCursor(StringRef BitcodeBytes) + : BitcodeBytes(arrayRefFromStringRef(BitcodeBytes)) {} + explicit SimpleBitstreamCursor(MemoryBufferRef BitcodeBytes) + : SimpleBitstreamCursor(BitcodeBytes.getBuffer()) {} + + bool canSkipToPos(size_t pos) const { + // pos can be skipped to if it is a valid address or one byte past the end. + return pos <= BitcodeBytes.size(); + } + + bool AtEndOfStream() { + return BitsInCurWord == 0 && BitcodeBytes.size() <= NextChar; + } + + /// Return the bit # of the bit we are reading. + uint64_t GetCurrentBitNo() const { + return NextChar*CHAR_BIT - BitsInCurWord; + } + + // Return the byte # of the current bit. + uint64_t getCurrentByteNo() const { return GetCurrentBitNo() / 8; } + + ArrayRef getBitcodeBytes() const { return BitcodeBytes; } + + /// Reset the stream to the specified bit number. + Error JumpToBit(uint64_t BitNo) { + size_t ByteNo = size_t(BitNo/8) & ~(sizeof(word_t)-1); + unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1)); + assert(canSkipToPos(ByteNo) && "Invalid location"); + + // Move the cursor to the right word. + NextChar = ByteNo; + BitsInCurWord = 0; + + // Skip over any bits that are already consumed. + if (WordBitNo) { + if (Expected Res = Read(WordBitNo)) + return Error::success(); + else + return Res.takeError(); + } + + return Error::success(); + } + + /// Get a pointer into the bitstream at the specified byte offset. + const uint8_t *getPointerToByte(uint64_t ByteNo, uint64_t NumBytes) { + return BitcodeBytes.data() + ByteNo; + } + + /// Get a pointer into the bitstream at the specified bit offset. + /// + /// The bit offset must be on a byte boundary. + const uint8_t *getPointerToBit(uint64_t BitNo, uint64_t NumBytes) { + assert(!(BitNo % 8) && "Expected bit on byte boundary"); + return getPointerToByte(BitNo / 8, NumBytes); + } + + Error fillCurWord() { + if (NextChar >= BitcodeBytes.size()) + return createStringError(std::errc::io_error, + "Unexpected end of file reading %u of %u bytes", + NextChar, BitcodeBytes.size()); + + // Read the next word from the stream. + const uint8_t *NextCharPtr = BitcodeBytes.data() + NextChar; + unsigned BytesRead; + if (BitcodeBytes.size() >= NextChar + sizeof(word_t)) { + BytesRead = sizeof(word_t); + CurWord = + support::endian::read( + NextCharPtr); + } else { + // Short read. + BytesRead = BitcodeBytes.size() - NextChar; + CurWord = 0; + for (unsigned B = 0; B != BytesRead; ++B) + CurWord |= uint64_t(NextCharPtr[B]) << (B * 8); + } + NextChar += BytesRead; + BitsInCurWord = BytesRead * 8; + return Error::success(); + } + + Expected Read(unsigned NumBits) { + static const unsigned BitsInWord = MaxChunkSize; + + assert(NumBits && NumBits <= BitsInWord && + "Cannot return zero or more than BitsInWord bits!"); + + static const unsigned Mask = sizeof(word_t) > 4 ? 0x3f : 0x1f; + + // If the field is fully contained by CurWord, return it quickly. + if (BitsInCurWord >= NumBits) { + word_t R = CurWord & (~word_t(0) >> (BitsInWord - NumBits)); + + // Use a mask to avoid undefined behavior. + CurWord >>= (NumBits & Mask); + + BitsInCurWord -= NumBits; + return R; + } + + word_t R = BitsInCurWord ? CurWord : 0; + unsigned BitsLeft = NumBits - BitsInCurWord; + + if (Error fillResult = fillCurWord()) + return std::move(fillResult); + + // If we run out of data, abort. + if (BitsLeft > BitsInCurWord) + return createStringError(std::errc::io_error, + "Unexpected end of file reading %u of %u bits", + BitsInCurWord, BitsLeft); + + word_t R2 = CurWord & (~word_t(0) >> (BitsInWord - BitsLeft)); + + // Use a mask to avoid undefined behavior. + CurWord >>= (BitsLeft & Mask); + + BitsInCurWord -= BitsLeft; + + R |= R2 << (NumBits - BitsLeft); + + return R; + } + + Expected ReadVBR(unsigned NumBits) { + Expected MaybeRead = Read(NumBits); + if (!MaybeRead) + return MaybeRead; + uint32_t Piece = MaybeRead.get(); + + if ((Piece & (1U << (NumBits-1))) == 0) + return Piece; + + uint32_t Result = 0; + unsigned NextBit = 0; + while (true) { + Result |= (Piece & ((1U << (NumBits-1))-1)) << NextBit; + + if ((Piece & (1U << (NumBits-1))) == 0) + return Result; + + NextBit += NumBits-1; + MaybeRead = Read(NumBits); + if (!MaybeRead) + return MaybeRead; + Piece = MaybeRead.get(); + } + } + + // Read a VBR that may have a value up to 64-bits in size. The chunk size of + // the VBR must still be <= 32 bits though. + Expected ReadVBR64(unsigned NumBits) { + Expected MaybeRead = Read(NumBits); + if (!MaybeRead) + return MaybeRead; + uint32_t Piece = MaybeRead.get(); + + if ((Piece & (1U << (NumBits-1))) == 0) + return uint64_t(Piece); + + uint64_t Result = 0; + unsigned NextBit = 0; + while (true) { + Result |= uint64_t(Piece & ((1U << (NumBits-1))-1)) << NextBit; + + if ((Piece & (1U << (NumBits-1))) == 0) + return Result; + + NextBit += NumBits-1; + MaybeRead = Read(NumBits); + if (!MaybeRead) + return MaybeRead; + Piece = MaybeRead.get(); + } + } + + void SkipToFourByteBoundary() { + // If word_t is 64-bits and if we've read less than 32 bits, just dump + // the bits we have up to the next 32-bit boundary. + if (sizeof(word_t) > 4 && + BitsInCurWord >= 32) { + CurWord >>= BitsInCurWord-32; + BitsInCurWord = 32; + return; + } + + BitsInCurWord = 0; + } + + /// Skip to the end of the file. + void skipToEnd() { NextChar = BitcodeBytes.size(); } +}; + +/// When advancing through a bitstream cursor, each advance can discover a few +/// different kinds of entries: +struct BitstreamEntry { + enum { + 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. + } 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; + } +}; + +/// This represents a position within a bitcode file, implemented on top of a +/// SimpleBitstreamCursor. +/// +/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not +/// be passed by value. +class BitstreamCursor : SimpleBitstreamCursor { + // This is the declared size of code values used for the current block, in + // bits. + unsigned CurCodeSize = 2; + + /// Abbrevs installed at in this block. + std::vector> CurAbbrevs; + + struct Block { + unsigned PrevCodeSize; + std::vector> PrevAbbrevs; + + explicit Block(unsigned PCS) : PrevCodeSize(PCS) {} + }; + + /// This tracks the codesize of parent blocks. + SmallVector BlockScope; + + BitstreamBlockInfo *BlockInfo = nullptr; + +public: + static const size_t MaxChunkSize = sizeof(word_t) * 8; + + BitstreamCursor() = default; + explicit BitstreamCursor(ArrayRef BitcodeBytes) + : SimpleBitstreamCursor(BitcodeBytes) {} + explicit BitstreamCursor(StringRef BitcodeBytes) + : SimpleBitstreamCursor(BitcodeBytes) {} + explicit BitstreamCursor(MemoryBufferRef BitcodeBytes) + : SimpleBitstreamCursor(BitcodeBytes) {} + + using SimpleBitstreamCursor::canSkipToPos; + using SimpleBitstreamCursor::AtEndOfStream; + using SimpleBitstreamCursor::getBitcodeBytes; + using SimpleBitstreamCursor::GetCurrentBitNo; + using SimpleBitstreamCursor::getCurrentByteNo; + using SimpleBitstreamCursor::getPointerToByte; + using SimpleBitstreamCursor::JumpToBit; + using SimpleBitstreamCursor::fillCurWord; + using SimpleBitstreamCursor::Read; + using SimpleBitstreamCursor::ReadVBR; + using SimpleBitstreamCursor::ReadVBR64; + + /// Return the number of bits used to encode an abbrev #. + unsigned getAbbrevIDWidth() const { return CurCodeSize; } + + /// Flags that modify the behavior of advance(). + enum { + /// If this flag is used, the advance() method does not automatically pop + /// the block scope when the end of a block is reached. + AF_DontPopBlockAtEnd = 1, + + /// If this flag is used, abbrev entries are returned just like normal + /// records. + AF_DontAutoprocessAbbrevs = 2 + }; + + /// Advance the current bitstream, returning the next entry in the stream. + Expected advance(unsigned Flags = 0) { + while (true) { + if (AtEndOfStream()) + return BitstreamEntry::getError(); + + Expected MaybeCode = ReadCode(); + if (!MaybeCode) + return MaybeCode.takeError(); + unsigned Code = MaybeCode.get(); + + if (Code == bitc::END_BLOCK) { + // Pop the end of the block unless Flags tells us not to. + if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd()) + return BitstreamEntry::getError(); + return BitstreamEntry::getEndBlock(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + if (Expected MaybeSubBlock = ReadSubBlockID()) + return BitstreamEntry::getSubBlock(MaybeSubBlock.get()); + else + return MaybeSubBlock.takeError(); + } + + if (Code == bitc::DEFINE_ABBREV && + !(Flags & AF_DontAutoprocessAbbrevs)) { + // We read and accumulate abbrev's, the client can't do anything with + // them anyway. + if (Error Err = ReadAbbrevRecord()) + return std::move(Err); + continue; + } + + return BitstreamEntry::getRecord(Code); + } + } + + /// This is a convenience function for clients that don't expect any + /// subblocks. This just skips over them automatically. + Expected advanceSkippingSubblocks(unsigned Flags = 0) { + while (true) { + // If we found a normal entry, return it. + Expected MaybeEntry = advance(Flags); + if (!MaybeEntry) + return MaybeEntry; + BitstreamEntry Entry = MaybeEntry.get(); + + if (Entry.Kind != BitstreamEntry::SubBlock) + return Entry; + + // If we found a sub-block, just skip over it and check the next entry. + if (Error Err = SkipBlock()) + return std::move(Err); + } + } + + Expected ReadCode() { return Read(CurCodeSize); } + + // Block header: + // [ENTER_SUBBLOCK, blockid, newcodelen, , blocklen] + + /// Having read the ENTER_SUBBLOCK code, read the BlockID for the block. + Expected ReadSubBlockID() { return ReadVBR(bitc::BlockIDWidth); } + + /// Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body + /// of this block. + Error SkipBlock() { + // Read and ignore the codelen value. + if (Expected Res = ReadVBR(bitc::CodeLenWidth)) + ; // Since we are skipping this block, we don't care what code widths are + // used inside of it. + else + return Res.takeError(); + + SkipToFourByteBoundary(); + Expected MaybeNum = Read(bitc::BlockSizeWidth); + if (!MaybeNum) + return MaybeNum.takeError(); + size_t NumFourBytes = MaybeNum.get(); + + // Check that the block wasn't partially defined, and that the offset isn't + // bogus. + size_t SkipTo = GetCurrentBitNo() + NumFourBytes * 4 * 8; + if (AtEndOfStream()) + return createStringError(std::errc::illegal_byte_sequence, + "can't skip block: already at end of stream"); + if (!canSkipToPos(SkipTo / 8)) + return createStringError(std::errc::illegal_byte_sequence, + "can't skip to bit %zu from %" PRIu64, SkipTo, + GetCurrentBitNo()); + + if (Error Res = JumpToBit(SkipTo)) + return Res; + + return Error::success(); + } + + /// Having read the ENTER_SUBBLOCK abbrevid, and enter the block. + Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr); + + bool ReadBlockEnd() { + if (BlockScope.empty()) return true; + + // Block tail: + // [END_BLOCK, ] + SkipToFourByteBoundary(); + + popBlockScope(); + return false; + } + +private: + void popBlockScope() { + CurCodeSize = BlockScope.back().PrevCodeSize; + + CurAbbrevs = std::move(BlockScope.back().PrevAbbrevs); + BlockScope.pop_back(); + } + + //===--------------------------------------------------------------------===// + // Record Processing + //===--------------------------------------------------------------------===// + +public: + /// Return the abbreviation for the specified AbbrevId. + const BitCodeAbbrev *getAbbrev(unsigned AbbrevID) { + unsigned AbbrevNo = AbbrevID - bitc::FIRST_APPLICATION_ABBREV; + if (AbbrevNo >= CurAbbrevs.size()) + report_fatal_error("Invalid abbrev number"); + return CurAbbrevs[AbbrevNo].get(); + } + + /// Read the current record and discard it, returning the code for the record. + Expected skipRecord(unsigned AbbrevID); + + Expected readRecord(unsigned AbbrevID, + SmallVectorImpl &Vals, + StringRef *Blob = nullptr); + + //===--------------------------------------------------------------------===// + // Abbrev Processing + //===--------------------------------------------------------------------===// + Error ReadAbbrevRecord(); + + /// Read and return a block info block from the bitstream. If an error was + /// encountered, return None. + /// + /// \param ReadBlockInfoNames Whether to read block/record name information in + /// the BlockInfo block. Only llvm-bcanalyzer uses this. + Expected> + ReadBlockInfoBlock(bool ReadBlockInfoNames = false); + + /// Set the block info to be used by this BitstreamCursor to interpret + /// abbreviated records. + void setBlockInfo(BitstreamBlockInfo *BI) { BlockInfo = BI; } +}; + +} // end llvm namespace + +#endif // LLVM_BITSTREAM_BITSTREAMREADER_H Index: llvm/trunk/include/llvm/Bitstream/BitstreamWriter.h =================================================================== --- llvm/trunk/include/llvm/Bitstream/BitstreamWriter.h +++ llvm/trunk/include/llvm/Bitstream/BitstreamWriter.h @@ -0,0 +1,547 @@ +//===- BitstreamWriter.h - Low-level bitstream writer interface -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitstreamWriter class. This class can be used to +// write an arbitrary bitstream, regardless of its contents. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BITSTREAM_BITSTREAMWRITER_H +#define LLVM_BITSTREAM_BITSTREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Support/Endian.h" +#include + +namespace llvm { + +class BitstreamWriter { + SmallVectorImpl &Out; + + /// CurBit - Always between 0 and 31 inclusive, specifies the next bit to use. + unsigned CurBit; + + /// CurValue - The current value. Only bits < CurBit are valid. + uint32_t CurValue; + + /// CurCodeSize - This is the declared size of code values used for the + /// current block, in bits. + unsigned CurCodeSize; + + /// BlockInfoCurBID - When emitting a BLOCKINFO_BLOCK, this is the currently + /// selected BLOCK ID. + unsigned BlockInfoCurBID; + + /// CurAbbrevs - Abbrevs installed at in this block. + std::vector> CurAbbrevs; + + struct Block { + unsigned PrevCodeSize; + size_t StartSizeWord; + std::vector> PrevAbbrevs; + Block(unsigned PCS, size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {} + }; + + /// BlockScope - This tracks the current blocks that we have entered. + std::vector BlockScope; + + /// BlockInfo - This contains information emitted to BLOCKINFO_BLOCK blocks. + /// These describe abbreviations that all blocks of the specified ID inherit. + struct BlockInfo { + unsigned BlockID; + std::vector> Abbrevs; + }; + std::vector BlockInfoRecords; + + void WriteByte(unsigned char Value) { + Out.push_back(Value); + } + + void WriteWord(unsigned Value) { + Value = support::endian::byte_swap(Value); + Out.append(reinterpret_cast(&Value), + reinterpret_cast(&Value + 1)); + } + + size_t GetBufferOffset() const { return Out.size(); } + + size_t GetWordIndex() const { + size_t Offset = GetBufferOffset(); + assert((Offset & 3) == 0 && "Not 32-bit aligned"); + return Offset / 4; + } + +public: + explicit BitstreamWriter(SmallVectorImpl &O) + : Out(O), CurBit(0), CurValue(0), CurCodeSize(2) {} + + ~BitstreamWriter() { + assert(CurBit == 0 && "Unflushed data remaining"); + assert(BlockScope.empty() && CurAbbrevs.empty() && "Block imbalance"); + } + + /// Retrieve the current position in the stream, in bits. + uint64_t GetCurrentBitNo() const { return GetBufferOffset() * 8 + CurBit; } + + /// Retrieve the number of bits currently used to encode an abbrev ID. + unsigned GetAbbrevIDWidth() const { return CurCodeSize; } + + //===--------------------------------------------------------------------===// + // Basic Primitives for emitting bits to the stream. + //===--------------------------------------------------------------------===// + + /// Backpatch a 32-bit word in the output at the given bit offset + /// with the specified value. + void BackpatchWord(uint64_t BitNo, unsigned NewWord) { + using namespace llvm::support; + unsigned ByteNo = BitNo / 8; + assert((!endian::readAtBitAlignment( + &Out[ByteNo], BitNo & 7)) && + "Expected to be patching over 0-value placeholders"); + endian::writeAtBitAlignment( + &Out[ByteNo], NewWord, BitNo & 7); + } + + void BackpatchWord64(uint64_t BitNo, uint64_t Val) { + BackpatchWord(BitNo, (uint32_t)Val); + BackpatchWord(BitNo + 32, (uint32_t)(Val >> 32)); + } + + void Emit(uint32_t Val, unsigned NumBits) { + assert(NumBits && NumBits <= 32 && "Invalid value size!"); + assert((Val & ~(~0U >> (32-NumBits))) == 0 && "High bits set!"); + CurValue |= Val << CurBit; + if (CurBit + NumBits < 32) { + CurBit += NumBits; + return; + } + + // Add the current word. + WriteWord(CurValue); + + if (CurBit) + CurValue = Val >> (32-CurBit); + else + CurValue = 0; + CurBit = (CurBit+NumBits) & 31; + } + + void FlushToWord() { + if (CurBit) { + WriteWord(CurValue); + CurBit = 0; + CurValue = 0; + } + } + + void EmitVBR(uint32_t Val, unsigned NumBits) { + assert(NumBits <= 32 && "Too many bits to emit!"); + uint32_t Threshold = 1U << (NumBits-1); + + // Emit the bits with VBR encoding, NumBits-1 bits at a time. + while (Val >= Threshold) { + Emit((Val & ((1 << (NumBits-1))-1)) | (1 << (NumBits-1)), NumBits); + Val >>= NumBits-1; + } + + Emit(Val, NumBits); + } + + void EmitVBR64(uint64_t Val, unsigned NumBits) { + assert(NumBits <= 32 && "Too many bits to emit!"); + if ((uint32_t)Val == Val) + return EmitVBR((uint32_t)Val, NumBits); + + uint32_t Threshold = 1U << (NumBits-1); + + // Emit the bits with VBR encoding, NumBits-1 bits at a time. + while (Val >= Threshold) { + Emit(((uint32_t)Val & ((1 << (NumBits-1))-1)) | + (1 << (NumBits-1)), NumBits); + Val >>= NumBits-1; + } + + Emit((uint32_t)Val, NumBits); + } + + /// EmitCode - Emit the specified code. + void EmitCode(unsigned Val) { + Emit(Val, CurCodeSize); + } + + //===--------------------------------------------------------------------===// + // Block Manipulation + //===--------------------------------------------------------------------===// + + /// getBlockInfo - If there is block info for the specified ID, return it, + /// otherwise return null. + BlockInfo *getBlockInfo(unsigned BlockID) { + // Common case, the most recent entry matches BlockID. + if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID) + return &BlockInfoRecords.back(); + + for (unsigned i = 0, e = static_cast(BlockInfoRecords.size()); + i != e; ++i) + if (BlockInfoRecords[i].BlockID == BlockID) + return &BlockInfoRecords[i]; + return nullptr; + } + + void EnterSubblock(unsigned BlockID, unsigned CodeLen) { + // Block header: + // [ENTER_SUBBLOCK, blockid, newcodelen, , blocklen] + EmitCode(bitc::ENTER_SUBBLOCK); + EmitVBR(BlockID, bitc::BlockIDWidth); + EmitVBR(CodeLen, bitc::CodeLenWidth); + FlushToWord(); + + size_t BlockSizeWordIndex = GetWordIndex(); + unsigned OldCodeSize = CurCodeSize; + + // Emit a placeholder, which will be replaced when the block is popped. + Emit(0, bitc::BlockSizeWidth); + + CurCodeSize = CodeLen; + + // Push the outer block's abbrev set onto the stack, start out with an + // empty abbrev set. + BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex); + BlockScope.back().PrevAbbrevs.swap(CurAbbrevs); + + // If there is a blockinfo for this BlockID, add all the predefined abbrevs + // to the abbrev list. + if (BlockInfo *Info = getBlockInfo(BlockID)) { + CurAbbrevs.insert(CurAbbrevs.end(), Info->Abbrevs.begin(), + Info->Abbrevs.end()); + } + } + + void ExitBlock() { + assert(!BlockScope.empty() && "Block scope imbalance!"); + const Block &B = BlockScope.back(); + + // Block tail: + // [END_BLOCK, ] + EmitCode(bitc::END_BLOCK); + FlushToWord(); + + // Compute the size of the block, in words, not counting the size field. + size_t SizeInWords = GetWordIndex() - B.StartSizeWord - 1; + uint64_t BitNo = uint64_t(B.StartSizeWord) * 32; + + // Update the block size field in the header of this sub-block. + BackpatchWord(BitNo, SizeInWords); + + // Restore the inner block's code size and abbrev table. + CurCodeSize = B.PrevCodeSize; + CurAbbrevs = std::move(B.PrevAbbrevs); + BlockScope.pop_back(); + } + + //===--------------------------------------------------------------------===// + // Record Emission + //===--------------------------------------------------------------------===// + +private: + /// EmitAbbreviatedLiteral - Emit a literal value according to its abbrev + /// record. This is a no-op, since the abbrev specifies the literal to use. + template + void EmitAbbreviatedLiteral(const BitCodeAbbrevOp &Op, uintty V) { + assert(Op.isLiteral() && "Not a literal"); + // If the abbrev specifies the literal value to use, don't emit + // anything. + assert(V == Op.getLiteralValue() && + "Invalid abbrev for record!"); + } + + /// EmitAbbreviatedField - Emit a single scalar field value with the specified + /// encoding. + template + void EmitAbbreviatedField(const BitCodeAbbrevOp &Op, uintty V) { + assert(!Op.isLiteral() && "Literals should use EmitAbbreviatedLiteral!"); + + // Encode the value as we are commanded. + switch (Op.getEncoding()) { + default: llvm_unreachable("Unknown encoding!"); + case BitCodeAbbrevOp::Fixed: + if (Op.getEncodingData()) + Emit((unsigned)V, (unsigned)Op.getEncodingData()); + break; + case BitCodeAbbrevOp::VBR: + if (Op.getEncodingData()) + EmitVBR64(V, (unsigned)Op.getEncodingData()); + break; + case BitCodeAbbrevOp::Char6: + Emit(BitCodeAbbrevOp::EncodeChar6((char)V), 6); + break; + } + } + + /// EmitRecordWithAbbrevImpl - This is the core implementation of the record + /// emission code. If BlobData is non-null, then it specifies an array of + /// data that should be emitted as part of the Blob or Array operand that is + /// known to exist at the end of the record. If Code is specified, then + /// it is the record code to emit before the Vals, which must not contain + /// the code. + template + void EmitRecordWithAbbrevImpl(unsigned Abbrev, ArrayRef Vals, + StringRef Blob, Optional Code) { + const char *BlobData = Blob.data(); + unsigned BlobLen = (unsigned) Blob.size(); + unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV; + assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!"); + const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get(); + + EmitCode(Abbrev); + + unsigned i = 0, e = static_cast(Abbv->getNumOperandInfos()); + if (Code) { + assert(e && "Expected non-empty abbreviation"); + const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i++); + + if (Op.isLiteral()) + EmitAbbreviatedLiteral(Op, Code.getValue()); + else { + assert(Op.getEncoding() != BitCodeAbbrevOp::Array && + Op.getEncoding() != BitCodeAbbrevOp::Blob && + "Expected literal or scalar"); + EmitAbbreviatedField(Op, Code.getValue()); + } + } + + unsigned RecordIdx = 0; + for (; i != e; ++i) { + const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); + if (Op.isLiteral()) { + assert(RecordIdx < Vals.size() && "Invalid abbrev/record"); + EmitAbbreviatedLiteral(Op, Vals[RecordIdx]); + ++RecordIdx; + } else if (Op.getEncoding() == BitCodeAbbrevOp::Array) { + // Array case. + assert(i + 2 == e && "array op not second to last?"); + const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); + + // If this record has blob data, emit it, otherwise we must have record + // entries to encode this way. + if (BlobData) { + assert(RecordIdx == Vals.size() && + "Blob data and record entries specified for array!"); + // Emit a vbr6 to indicate the number of elements present. + EmitVBR(static_cast(BlobLen), 6); + + // Emit each field. + for (unsigned i = 0; i != BlobLen; ++i) + EmitAbbreviatedField(EltEnc, (unsigned char)BlobData[i]); + + // Know that blob data is consumed for assertion below. + BlobData = nullptr; + } else { + // Emit a vbr6 to indicate the number of elements present. + EmitVBR(static_cast(Vals.size()-RecordIdx), 6); + + // Emit each field. + for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx) + EmitAbbreviatedField(EltEnc, Vals[RecordIdx]); + } + } else if (Op.getEncoding() == BitCodeAbbrevOp::Blob) { + // If this record has blob data, emit it, otherwise we must have record + // entries to encode this way. + + if (BlobData) { + assert(RecordIdx == Vals.size() && + "Blob data and record entries specified for blob operand!"); + + assert(Blob.data() == BlobData && "BlobData got moved"); + assert(Blob.size() == BlobLen && "BlobLen got changed"); + emitBlob(Blob); + BlobData = nullptr; + } else { + emitBlob(Vals.slice(RecordIdx)); + } + } else { // Single scalar field. + assert(RecordIdx < Vals.size() && "Invalid abbrev/record"); + EmitAbbreviatedField(Op, Vals[RecordIdx]); + ++RecordIdx; + } + } + assert(RecordIdx == Vals.size() && "Not all record operands emitted!"); + assert(BlobData == nullptr && + "Blob data specified for record that doesn't use it!"); + } + +public: + /// Emit a blob, including flushing before and tail-padding. + template + void emitBlob(ArrayRef Bytes, bool ShouldEmitSize = true) { + // Emit a vbr6 to indicate the number of elements present. + if (ShouldEmitSize) + EmitVBR(static_cast(Bytes.size()), 6); + + // Flush to a 32-bit alignment boundary. + FlushToWord(); + + // Emit literal bytes. + for (const auto &B : Bytes) { + assert(isUInt<8>(B) && "Value too large to emit as byte"); + WriteByte((unsigned char)B); + } + + // Align end to 32-bits. + while (GetBufferOffset() & 3) + WriteByte(0); + } + void emitBlob(StringRef Bytes, bool ShouldEmitSize = true) { + emitBlob(makeArrayRef((const uint8_t *)Bytes.data(), Bytes.size()), + ShouldEmitSize); + } + + /// EmitRecord - Emit the specified record to the stream, using an abbrev if + /// we have one to compress the output. + template + void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev = 0) { + if (!Abbrev) { + // If we don't have an abbrev to use, emit this in its fully unabbreviated + // form. + auto Count = static_cast(makeArrayRef(Vals).size()); + EmitCode(bitc::UNABBREV_RECORD); + EmitVBR(Code, 6); + EmitVBR(Count, 6); + for (unsigned i = 0, e = Count; i != e; ++i) + EmitVBR64(Vals[i], 6); + return; + } + + EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), StringRef(), Code); + } + + /// EmitRecordWithAbbrev - Emit a record with the specified abbreviation. + /// Unlike EmitRecord, the code for the record should be included in Vals as + /// the first entry. + template + void EmitRecordWithAbbrev(unsigned Abbrev, const Container &Vals) { + EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), StringRef(), None); + } + + /// EmitRecordWithBlob - Emit the specified record to the stream, using an + /// abbrev that includes a blob at the end. The blob data to emit is + /// specified by the pointer and length specified at the end. In contrast to + /// EmitRecord, this routine expects that the first entry in Vals is the code + /// of the record. + template + void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, + StringRef Blob) { + EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), Blob, None); + } + template + void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, + const char *BlobData, unsigned BlobLen) { + return EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), + StringRef(BlobData, BlobLen), None); + } + + /// EmitRecordWithArray - Just like EmitRecordWithBlob, works with records + /// that end with an array. + template + void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, + StringRef Array) { + EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), Array, None); + } + template + void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, + const char *ArrayData, unsigned ArrayLen) { + return EmitRecordWithAbbrevImpl(Abbrev, makeArrayRef(Vals), + StringRef(ArrayData, ArrayLen), None); + } + + //===--------------------------------------------------------------------===// + // Abbrev Emission + //===--------------------------------------------------------------------===// + +private: + // Emit the abbreviation as a DEFINE_ABBREV record. + void EncodeAbbrev(const BitCodeAbbrev &Abbv) { + EmitCode(bitc::DEFINE_ABBREV); + EmitVBR(Abbv.getNumOperandInfos(), 5); + for (unsigned i = 0, e = static_cast(Abbv.getNumOperandInfos()); + i != e; ++i) { + const BitCodeAbbrevOp &Op = Abbv.getOperandInfo(i); + Emit(Op.isLiteral(), 1); + if (Op.isLiteral()) { + EmitVBR64(Op.getLiteralValue(), 8); + } else { + Emit(Op.getEncoding(), 3); + if (Op.hasEncodingData()) + EmitVBR64(Op.getEncodingData(), 5); + } + } + } +public: + + /// Emits the abbreviation \p Abbv to the stream. + unsigned EmitAbbrev(std::shared_ptr Abbv) { + EncodeAbbrev(*Abbv); + CurAbbrevs.push_back(std::move(Abbv)); + return static_cast(CurAbbrevs.size())-1 + + bitc::FIRST_APPLICATION_ABBREV; + } + + //===--------------------------------------------------------------------===// + // BlockInfo Block Emission + //===--------------------------------------------------------------------===// + + /// EnterBlockInfoBlock - Start emitting the BLOCKINFO_BLOCK. + void EnterBlockInfoBlock() { + EnterSubblock(bitc::BLOCKINFO_BLOCK_ID, 2); + BlockInfoCurBID = ~0U; + BlockInfoRecords.clear(); + } +private: + /// SwitchToBlockID - If we aren't already talking about the specified block + /// ID, emit a BLOCKINFO_CODE_SETBID record. + void SwitchToBlockID(unsigned BlockID) { + if (BlockInfoCurBID == BlockID) return; + SmallVector V; + V.push_back(BlockID); + EmitRecord(bitc::BLOCKINFO_CODE_SETBID, V); + BlockInfoCurBID = BlockID; + } + + BlockInfo &getOrCreateBlockInfo(unsigned BlockID) { + if (BlockInfo *BI = getBlockInfo(BlockID)) + return *BI; + + // Otherwise, add a new record. + BlockInfoRecords.emplace_back(); + BlockInfoRecords.back().BlockID = BlockID; + return BlockInfoRecords.back(); + } + +public: + + /// EmitBlockInfoAbbrev - Emit a DEFINE_ABBREV record for the specified + /// BlockID. + unsigned EmitBlockInfoAbbrev(unsigned BlockID, std::shared_ptr Abbv) { + SwitchToBlockID(BlockID); + EncodeAbbrev(*Abbv); + + // Add the abbrev to the specified block record. + BlockInfo &Info = getOrCreateBlockInfo(BlockID); + Info.Abbrevs.push_back(std::move(Abbv)); + + return Info.Abbrevs.size()-1+bitc::FIRST_APPLICATION_ABBREV; + } +}; + + +} // End llvm namespace + +#endif Index: llvm/trunk/include/llvm/Support/JSON.h =================================================================== --- llvm/trunk/include/llvm/Support/JSON.h +++ llvm/trunk/include/llvm/Support/JSON.h @@ -39,7 +39,7 @@ /// /// - LLVM bitstream is a space- and CPU- efficient binary format. Typically it /// encodes LLVM IR ("bitcode"), but it can be a container for other data. -/// Low-level reader/writer libraries are in Bitcode/Bitstream*.h +/// Low-level reader/writer libraries are in Bitstream/Bitstream*.h /// //===---------------------------------------------------------------------===// Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -20,7 +20,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" Index: llvm/trunk/lib/Bitcode/Reader/BitstreamReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitstreamReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitstreamReader.cpp @@ -1,510 +0,0 @@ -//===- BitstreamReader.cpp - BitstreamReader implementation ---------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/ADT/StringRef.h" -#include -#include - -using namespace llvm; - -//===----------------------------------------------------------------------===// -// BitstreamCursor implementation -//===----------------------------------------------------------------------===// - -/// Having read the ENTER_SUBBLOCK abbrevid, enter the block. -Error BitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) { - // Save the current block's state on BlockScope. - BlockScope.push_back(Block(CurCodeSize)); - BlockScope.back().PrevAbbrevs.swap(CurAbbrevs); - - // Add the abbrevs specific to this block to the CurAbbrevs list. - if (BlockInfo) { - if (const BitstreamBlockInfo::BlockInfo *Info = - BlockInfo->getBlockInfo(BlockID)) { - CurAbbrevs.insert(CurAbbrevs.end(), Info->Abbrevs.begin(), - Info->Abbrevs.end()); - } - } - - // Get the codesize of this block. - Expected MaybeVBR = ReadVBR(bitc::CodeLenWidth); - if (!MaybeVBR) - return MaybeVBR.takeError(); - CurCodeSize = MaybeVBR.get(); - - if (CurCodeSize > MaxChunkSize) - return llvm::createStringError( - std::errc::illegal_byte_sequence, - "can't read more than %zu at a time, trying to read %u", +MaxChunkSize, - CurCodeSize); - - SkipToFourByteBoundary(); - Expected MaybeNum = Read(bitc::BlockSizeWidth); - if (!MaybeNum) - return MaybeNum.takeError(); - word_t NumWords = MaybeNum.get(); - if (NumWordsP) - *NumWordsP = NumWords; - - if (CurCodeSize == 0) - return llvm::createStringError( - std::errc::illegal_byte_sequence, - "can't enter sub-block: current code size is 0"); - if (AtEndOfStream()) - return llvm::createStringError( - std::errc::illegal_byte_sequence, - "can't enter sub block: already at end of stream"); - - return Error::success(); -} - -static Expected readAbbreviatedField(BitstreamCursor &Cursor, - const BitCodeAbbrevOp &Op) { - assert(!Op.isLiteral() && "Not to be used with literals!"); - - // Decode the value as we are commanded. - switch (Op.getEncoding()) { - case BitCodeAbbrevOp::Array: - case BitCodeAbbrevOp::Blob: - llvm_unreachable("Should not reach here"); - case BitCodeAbbrevOp::Fixed: - assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); - return Cursor.Read((unsigned)Op.getEncodingData()); - case BitCodeAbbrevOp::VBR: - assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); - return Cursor.ReadVBR64((unsigned)Op.getEncodingData()); - case BitCodeAbbrevOp::Char6: - if (Expected Res = Cursor.Read(6)) - return BitCodeAbbrevOp::DecodeChar6(Res.get()); - else - return Res.takeError(); - } - llvm_unreachable("invalid abbreviation encoding"); -} - -static Error skipAbbreviatedField(BitstreamCursor &Cursor, - const BitCodeAbbrevOp &Op) { - assert(!Op.isLiteral() && "Not to be used with literals!"); - - // Decode the value as we are commanded. - switch (Op.getEncoding()) { - case BitCodeAbbrevOp::Array: - case BitCodeAbbrevOp::Blob: - llvm_unreachable("Should not reach here"); - case BitCodeAbbrevOp::Fixed: - assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); - if (Expected Res = Cursor.Read((unsigned)Op.getEncodingData())) - break; - else - return Res.takeError(); - case BitCodeAbbrevOp::VBR: - assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); - if (Expected Res = - Cursor.ReadVBR64((unsigned)Op.getEncodingData())) - break; - else - return Res.takeError(); - case BitCodeAbbrevOp::Char6: - if (Expected Res = Cursor.Read(6)) - break; - else - return Res.takeError(); - } - return ErrorSuccess(); -} - -/// skipRecord - Read the current record and discard it. -Expected BitstreamCursor::skipRecord(unsigned AbbrevID) { - // Skip unabbreviated records by reading past their entries. - if (AbbrevID == bitc::UNABBREV_RECORD) { - Expected MaybeCode = ReadVBR(6); - if (!MaybeCode) - return MaybeCode.takeError(); - unsigned Code = MaybeCode.get(); - Expected MaybeVBR = ReadVBR(6); - if (!MaybeVBR) - return MaybeVBR.get(); - unsigned NumElts = MaybeVBR.get(); - for (unsigned i = 0; i != NumElts; ++i) - if (Expected Res = ReadVBR64(6)) - ; // Skip! - else - return Res.takeError(); - return Code; - } - - const BitCodeAbbrev *Abbv = getAbbrev(AbbrevID); - const BitCodeAbbrevOp &CodeOp = Abbv->getOperandInfo(0); - unsigned Code; - if (CodeOp.isLiteral()) - Code = CodeOp.getLiteralValue(); - else { - if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array || - CodeOp.getEncoding() == BitCodeAbbrevOp::Blob) - return llvm::createStringError( - std::errc::illegal_byte_sequence, - "Abbreviation starts with an Array or a Blob"); - Expected MaybeCode = readAbbreviatedField(*this, CodeOp); - if (!MaybeCode) - return MaybeCode.takeError(); - Code = MaybeCode.get(); - } - - for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i < e; ++i) { - const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); - if (Op.isLiteral()) - continue; - - if (Op.getEncoding() != BitCodeAbbrevOp::Array && - Op.getEncoding() != BitCodeAbbrevOp::Blob) { - if (Error Err = skipAbbreviatedField(*this, Op)) - return std::move(Err); - continue; - } - - if (Op.getEncoding() == BitCodeAbbrevOp::Array) { - // Array case. Read the number of elements as a vbr6. - Expected MaybeNum = ReadVBR(6); - if (!MaybeNum) - return MaybeNum.takeError(); - unsigned NumElts = MaybeNum.get(); - - // Get the element encoding. - assert(i+2 == e && "array op not second to last?"); - const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); - - // Read all the elements. - // Decode the value as we are commanded. - switch (EltEnc.getEncoding()) { - default: - report_fatal_error("Array element type can't be an Array or a Blob"); - case BitCodeAbbrevOp::Fixed: - assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize); - if (Error Err = JumpToBit(GetCurrentBitNo() + - NumElts * EltEnc.getEncodingData())) - return std::move(Err); - break; - case BitCodeAbbrevOp::VBR: - assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize); - for (; NumElts; --NumElts) - if (Expected Res = - ReadVBR64((unsigned)EltEnc.getEncodingData())) - ; // Skip! - else - return Res.takeError(); - break; - case BitCodeAbbrevOp::Char6: - if (Error Err = JumpToBit(GetCurrentBitNo() + NumElts * 6)) - return std::move(Err); - break; - } - continue; - } - - assert(Op.getEncoding() == BitCodeAbbrevOp::Blob); - // Blob case. Read the number of bytes as a vbr6. - Expected MaybeNum = ReadVBR(6); - if (!MaybeNum) - return MaybeNum.takeError(); - unsigned NumElts = MaybeNum.get(); - SkipToFourByteBoundary(); // 32-bit alignment - - // Figure out where the end of this blob will be including tail padding. - size_t NewEnd = GetCurrentBitNo()+((NumElts+3)&~3)*8; - - // If this would read off the end of the bitcode file, just set the - // record to empty and return. - if (!canSkipToPos(NewEnd/8)) { - skipToEnd(); - break; - } - - // Skip over the blob. - if (Error Err = JumpToBit(NewEnd)) - return std::move(Err); - } - return Code; -} - -Expected BitstreamCursor::readRecord(unsigned AbbrevID, - SmallVectorImpl &Vals, - StringRef *Blob) { - if (AbbrevID == bitc::UNABBREV_RECORD) { - Expected MaybeCode = ReadVBR(6); - if (!MaybeCode) - return MaybeCode.takeError(); - uint32_t Code = MaybeCode.get(); - Expected MaybeNumElts = ReadVBR(6); - if (!MaybeNumElts) - return MaybeNumElts.takeError(); - uint32_t NumElts = MaybeNumElts.get(); - - for (unsigned i = 0; i != NumElts; ++i) - if (Expected MaybeVal = ReadVBR64(6)) - Vals.push_back(MaybeVal.get()); - else - return MaybeVal.takeError(); - return Code; - } - - const BitCodeAbbrev *Abbv = getAbbrev(AbbrevID); - - // Read the record code first. - assert(Abbv->getNumOperandInfos() != 0 && "no record code in abbreviation?"); - const BitCodeAbbrevOp &CodeOp = Abbv->getOperandInfo(0); - unsigned Code; - if (CodeOp.isLiteral()) - Code = CodeOp.getLiteralValue(); - else { - if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array || - CodeOp.getEncoding() == BitCodeAbbrevOp::Blob) - report_fatal_error("Abbreviation starts with an Array or a Blob"); - if (Expected MaybeCode = readAbbreviatedField(*this, CodeOp)) - Code = MaybeCode.get(); - else - return MaybeCode.takeError(); - } - - for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) { - const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); - if (Op.isLiteral()) { - Vals.push_back(Op.getLiteralValue()); - continue; - } - - if (Op.getEncoding() != BitCodeAbbrevOp::Array && - Op.getEncoding() != BitCodeAbbrevOp::Blob) { - if (Expected MaybeVal = readAbbreviatedField(*this, Op)) - Vals.push_back(MaybeVal.get()); - else - return MaybeVal.takeError(); - continue; - } - - if (Op.getEncoding() == BitCodeAbbrevOp::Array) { - // Array case. Read the number of elements as a vbr6. - Expected MaybeNumElts = ReadVBR(6); - if (!MaybeNumElts) - return MaybeNumElts.takeError(); - uint32_t NumElts = MaybeNumElts.get(); - - // Get the element encoding. - if (i + 2 != e) - report_fatal_error("Array op not second to last"); - const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); - if (!EltEnc.isEncoding()) - report_fatal_error( - "Array element type has to be an encoding of a type"); - - // Read all the elements. - switch (EltEnc.getEncoding()) { - default: - report_fatal_error("Array element type can't be an Array or a Blob"); - case BitCodeAbbrevOp::Fixed: - for (; NumElts; --NumElts) - if (Expected MaybeVal = - Read((unsigned)EltEnc.getEncodingData())) - Vals.push_back(MaybeVal.get()); - else - return MaybeVal.takeError(); - break; - case BitCodeAbbrevOp::VBR: - for (; NumElts; --NumElts) - if (Expected MaybeVal = - ReadVBR64((unsigned)EltEnc.getEncodingData())) - Vals.push_back(MaybeVal.get()); - else - return MaybeVal.takeError(); - break; - case BitCodeAbbrevOp::Char6: - for (; NumElts; --NumElts) - if (Expected MaybeVal = Read(6)) - Vals.push_back(BitCodeAbbrevOp::DecodeChar6(MaybeVal.get())); - else - return MaybeVal.takeError(); - } - continue; - } - - assert(Op.getEncoding() == BitCodeAbbrevOp::Blob); - // Blob case. Read the number of bytes as a vbr6. - Expected MaybeNumElts = ReadVBR(6); - if (!MaybeNumElts) - return MaybeNumElts.takeError(); - uint32_t NumElts = MaybeNumElts.get(); - SkipToFourByteBoundary(); // 32-bit alignment - - // Figure out where the end of this blob will be including tail padding. - size_t CurBitPos = GetCurrentBitNo(); - size_t NewEnd = CurBitPos+((NumElts+3)&~3)*8; - - // If this would read off the end of the bitcode file, just set the - // record to empty and return. - if (!canSkipToPos(NewEnd/8)) { - Vals.append(NumElts, 0); - skipToEnd(); - break; - } - - // Otherwise, inform the streamer that we need these bytes in memory. Skip - // over tail padding first, in case jumping to NewEnd invalidates the Blob - // pointer. - if (Error Err = JumpToBit(NewEnd)) - return std::move(Err); - const char *Ptr = (const char *)getPointerToBit(CurBitPos, NumElts); - - // If we can return a reference to the data, do so to avoid copying it. - if (Blob) { - *Blob = StringRef(Ptr, NumElts); - } else { - // Otherwise, unpack into Vals with zero extension. - for (; NumElts; --NumElts) - Vals.push_back((unsigned char)*Ptr++); - } - } - - return Code; -} - -Error BitstreamCursor::ReadAbbrevRecord() { - auto Abbv = std::make_shared(); - Expected MaybeNumOpInfo = ReadVBR(5); - if (!MaybeNumOpInfo) - return MaybeNumOpInfo.takeError(); - unsigned NumOpInfo = MaybeNumOpInfo.get(); - for (unsigned i = 0; i != NumOpInfo; ++i) { - Expected MaybeIsLiteral = Read(1); - if (!MaybeIsLiteral) - return MaybeIsLiteral.takeError(); - bool IsLiteral = MaybeIsLiteral.get(); - if (IsLiteral) { - Expected MaybeOp = ReadVBR64(8); - if (!MaybeOp) - return MaybeOp.takeError(); - Abbv->Add(BitCodeAbbrevOp(MaybeOp.get())); - continue; - } - - Expected MaybeEncoding = Read(3); - if (!MaybeEncoding) - return MaybeEncoding.takeError(); - BitCodeAbbrevOp::Encoding E = - (BitCodeAbbrevOp::Encoding)MaybeEncoding.get(); - if (BitCodeAbbrevOp::hasEncodingData(E)) { - Expected MaybeData = ReadVBR64(5); - if (!MaybeData) - return MaybeData.takeError(); - uint64_t Data = MaybeData.get(); - - // As a special case, handle fixed(0) (i.e., a fixed field with zero bits) - // and vbr(0) as a literal zero. This is decoded the same way, and avoids - // a slow path in Read() to have to handle reading zero bits. - if ((E == BitCodeAbbrevOp::Fixed || E == BitCodeAbbrevOp::VBR) && - Data == 0) { - Abbv->Add(BitCodeAbbrevOp(0)); - continue; - } - - if ((E == BitCodeAbbrevOp::Fixed || E == BitCodeAbbrevOp::VBR) && - Data > MaxChunkSize) - report_fatal_error( - "Fixed or VBR abbrev record with size > MaxChunkData"); - - Abbv->Add(BitCodeAbbrevOp(E, Data)); - } else - Abbv->Add(BitCodeAbbrevOp(E)); - } - - if (Abbv->getNumOperandInfos() == 0) - report_fatal_error("Abbrev record with no operands"); - CurAbbrevs.push_back(std::move(Abbv)); - - return Error::success(); -} - -Expected> -BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) { - if (llvm::Error Err = EnterSubBlock(bitc::BLOCKINFO_BLOCK_ID)) - return std::move(Err); - - BitstreamBlockInfo NewBlockInfo; - - SmallVector Record; - BitstreamBlockInfo::BlockInfo *CurBlockInfo = nullptr; - - // Read all the records for this module. - while (true) { - Expected MaybeEntry = - advanceSkippingSubblocks(AF_DontAutoprocessAbbrevs); - if (!MaybeEntry) - return MaybeEntry.takeError(); - BitstreamEntry Entry = MaybeEntry.get(); - - switch (Entry.Kind) { - case llvm::BitstreamEntry::SubBlock: // Handled for us already. - case llvm::BitstreamEntry::Error: - return None; - case llvm::BitstreamEntry::EndBlock: - return std::move(NewBlockInfo); - case llvm::BitstreamEntry::Record: - // The interesting case. - break; - } - - // Read abbrev records, associate them with CurBID. - if (Entry.ID == bitc::DEFINE_ABBREV) { - if (!CurBlockInfo) return None; - if (Error Err = ReadAbbrevRecord()) - return std::move(Err); - - // ReadAbbrevRecord installs the abbrev in CurAbbrevs. Move it to the - // appropriate BlockInfo. - CurBlockInfo->Abbrevs.push_back(std::move(CurAbbrevs.back())); - CurAbbrevs.pop_back(); - continue; - } - - // Read a record. - Record.clear(); - Expected MaybeBlockInfo = readRecord(Entry.ID, Record); - if (!MaybeBlockInfo) - return MaybeBlockInfo.takeError(); - switch (MaybeBlockInfo.get()) { - default: - break; // Default behavior, ignore unknown content. - case bitc::BLOCKINFO_CODE_SETBID: - if (Record.size() < 1) - return None; - CurBlockInfo = &NewBlockInfo.getOrCreateBlockInfo((unsigned)Record[0]); - break; - case bitc::BLOCKINFO_CODE_BLOCKNAME: { - if (!CurBlockInfo) - return None; - if (!ReadBlockInfoNames) - break; // Ignore name. - std::string Name; - for (unsigned i = 0, e = Record.size(); i != e; ++i) - Name += (char)Record[i]; - CurBlockInfo->Name = Name; - break; - } - case bitc::BLOCKINFO_CODE_SETRECORDNAME: { - if (!CurBlockInfo) return None; - if (!ReadBlockInfoNames) - break; // Ignore name. - std::string Name; - for (unsigned i = 1, e = Record.size(); i != e; ++i) - Name += (char)Record[i]; - CurBlockInfo->RecordNames.push_back(std::make_pair((unsigned)Record[0], - Name)); - break; - } - } - } -} Index: llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt +++ llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt @@ -1,7 +1,6 @@ add_llvm_library(LLVMBitReader BitReader.cpp BitcodeReader.cpp - BitstreamReader.cpp MetadataLoader.cpp ValueList.cpp Index: llvm/trunk/lib/Bitcode/Reader/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/Bitcode/Reader/LLVMBuild.txt +++ llvm/trunk/lib/Bitcode/Reader/LLVMBuild.txt @@ -18,4 +18,4 @@ type = Library name = BitReader parent = Bitcode -required_libraries = Core Support +required_libraries = BitstreamReader Core Support Index: llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp @@ -22,7 +22,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -24,8 +24,8 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Attributes.h" Index: llvm/trunk/lib/Bitstream/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Bitstream/CMakeLists.txt +++ llvm/trunk/lib/Bitstream/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Reader) +# The writer is header-only. Index: llvm/trunk/lib/Bitstream/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/Bitstream/LLVMBuild.txt +++ llvm/trunk/lib/Bitstream/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Bitstream/LLVMBuild.txt ----------------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = Reader + +[component_0] +type = Group +name = Bitstream +parent = Libraries Index: llvm/trunk/lib/Bitstream/Reader/BitstreamReader.cpp =================================================================== --- llvm/trunk/lib/Bitstream/Reader/BitstreamReader.cpp +++ llvm/trunk/lib/Bitstream/Reader/BitstreamReader.cpp @@ -0,0 +1,510 @@ +//===- BitstreamReader.cpp - BitstreamReader implementation ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// BitstreamCursor implementation +//===----------------------------------------------------------------------===// + +/// Having read the ENTER_SUBBLOCK abbrevid, enter the block. +Error BitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) { + // Save the current block's state on BlockScope. + BlockScope.push_back(Block(CurCodeSize)); + BlockScope.back().PrevAbbrevs.swap(CurAbbrevs); + + // Add the abbrevs specific to this block to the CurAbbrevs list. + if (BlockInfo) { + if (const BitstreamBlockInfo::BlockInfo *Info = + BlockInfo->getBlockInfo(BlockID)) { + CurAbbrevs.insert(CurAbbrevs.end(), Info->Abbrevs.begin(), + Info->Abbrevs.end()); + } + } + + // Get the codesize of this block. + Expected MaybeVBR = ReadVBR(bitc::CodeLenWidth); + if (!MaybeVBR) + return MaybeVBR.takeError(); + CurCodeSize = MaybeVBR.get(); + + if (CurCodeSize > MaxChunkSize) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "can't read more than %zu at a time, trying to read %u", +MaxChunkSize, + CurCodeSize); + + SkipToFourByteBoundary(); + Expected MaybeNum = Read(bitc::BlockSizeWidth); + if (!MaybeNum) + return MaybeNum.takeError(); + word_t NumWords = MaybeNum.get(); + if (NumWordsP) + *NumWordsP = NumWords; + + if (CurCodeSize == 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "can't enter sub-block: current code size is 0"); + if (AtEndOfStream()) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "can't enter sub block: already at end of stream"); + + return Error::success(); +} + +static Expected readAbbreviatedField(BitstreamCursor &Cursor, + const BitCodeAbbrevOp &Op) { + assert(!Op.isLiteral() && "Not to be used with literals!"); + + // Decode the value as we are commanded. + switch (Op.getEncoding()) { + case BitCodeAbbrevOp::Array: + case BitCodeAbbrevOp::Blob: + llvm_unreachable("Should not reach here"); + case BitCodeAbbrevOp::Fixed: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); + return Cursor.Read((unsigned)Op.getEncodingData()); + case BitCodeAbbrevOp::VBR: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); + return Cursor.ReadVBR64((unsigned)Op.getEncodingData()); + case BitCodeAbbrevOp::Char6: + if (Expected Res = Cursor.Read(6)) + return BitCodeAbbrevOp::DecodeChar6(Res.get()); + else + return Res.takeError(); + } + llvm_unreachable("invalid abbreviation encoding"); +} + +static Error skipAbbreviatedField(BitstreamCursor &Cursor, + const BitCodeAbbrevOp &Op) { + assert(!Op.isLiteral() && "Not to be used with literals!"); + + // Decode the value as we are commanded. + switch (Op.getEncoding()) { + case BitCodeAbbrevOp::Array: + case BitCodeAbbrevOp::Blob: + llvm_unreachable("Should not reach here"); + case BitCodeAbbrevOp::Fixed: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); + if (Expected Res = Cursor.Read((unsigned)Op.getEncodingData())) + break; + else + return Res.takeError(); + case BitCodeAbbrevOp::VBR: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); + if (Expected Res = + Cursor.ReadVBR64((unsigned)Op.getEncodingData())) + break; + else + return Res.takeError(); + case BitCodeAbbrevOp::Char6: + if (Expected Res = Cursor.Read(6)) + break; + else + return Res.takeError(); + } + return ErrorSuccess(); +} + +/// skipRecord - Read the current record and discard it. +Expected BitstreamCursor::skipRecord(unsigned AbbrevID) { + // Skip unabbreviated records by reading past their entries. + if (AbbrevID == bitc::UNABBREV_RECORD) { + Expected MaybeCode = ReadVBR(6); + if (!MaybeCode) + return MaybeCode.takeError(); + unsigned Code = MaybeCode.get(); + Expected MaybeVBR = ReadVBR(6); + if (!MaybeVBR) + return MaybeVBR.get(); + unsigned NumElts = MaybeVBR.get(); + for (unsigned i = 0; i != NumElts; ++i) + if (Expected Res = ReadVBR64(6)) + ; // Skip! + else + return Res.takeError(); + return Code; + } + + const BitCodeAbbrev *Abbv = getAbbrev(AbbrevID); + const BitCodeAbbrevOp &CodeOp = Abbv->getOperandInfo(0); + unsigned Code; + if (CodeOp.isLiteral()) + Code = CodeOp.getLiteralValue(); + else { + if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array || + CodeOp.getEncoding() == BitCodeAbbrevOp::Blob) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "Abbreviation starts with an Array or a Blob"); + Expected MaybeCode = readAbbreviatedField(*this, CodeOp); + if (!MaybeCode) + return MaybeCode.takeError(); + Code = MaybeCode.get(); + } + + for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i < e; ++i) { + const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); + if (Op.isLiteral()) + continue; + + if (Op.getEncoding() != BitCodeAbbrevOp::Array && + Op.getEncoding() != BitCodeAbbrevOp::Blob) { + if (Error Err = skipAbbreviatedField(*this, Op)) + return std::move(Err); + continue; + } + + if (Op.getEncoding() == BitCodeAbbrevOp::Array) { + // Array case. Read the number of elements as a vbr6. + Expected MaybeNum = ReadVBR(6); + if (!MaybeNum) + return MaybeNum.takeError(); + unsigned NumElts = MaybeNum.get(); + + // Get the element encoding. + assert(i+2 == e && "array op not second to last?"); + const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); + + // Read all the elements. + // Decode the value as we are commanded. + switch (EltEnc.getEncoding()) { + default: + report_fatal_error("Array element type can't be an Array or a Blob"); + case BitCodeAbbrevOp::Fixed: + assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize); + if (Error Err = JumpToBit(GetCurrentBitNo() + + NumElts * EltEnc.getEncodingData())) + return std::move(Err); + break; + case BitCodeAbbrevOp::VBR: + assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize); + for (; NumElts; --NumElts) + if (Expected Res = + ReadVBR64((unsigned)EltEnc.getEncodingData())) + ; // Skip! + else + return Res.takeError(); + break; + case BitCodeAbbrevOp::Char6: + if (Error Err = JumpToBit(GetCurrentBitNo() + NumElts * 6)) + return std::move(Err); + break; + } + continue; + } + + assert(Op.getEncoding() == BitCodeAbbrevOp::Blob); + // Blob case. Read the number of bytes as a vbr6. + Expected MaybeNum = ReadVBR(6); + if (!MaybeNum) + return MaybeNum.takeError(); + unsigned NumElts = MaybeNum.get(); + SkipToFourByteBoundary(); // 32-bit alignment + + // Figure out where the end of this blob will be including tail padding. + size_t NewEnd = GetCurrentBitNo()+((NumElts+3)&~3)*8; + + // If this would read off the end of the bitcode file, just set the + // record to empty and return. + if (!canSkipToPos(NewEnd/8)) { + skipToEnd(); + break; + } + + // Skip over the blob. + if (Error Err = JumpToBit(NewEnd)) + return std::move(Err); + } + return Code; +} + +Expected BitstreamCursor::readRecord(unsigned AbbrevID, + SmallVectorImpl &Vals, + StringRef *Blob) { + if (AbbrevID == bitc::UNABBREV_RECORD) { + Expected MaybeCode = ReadVBR(6); + if (!MaybeCode) + return MaybeCode.takeError(); + uint32_t Code = MaybeCode.get(); + Expected MaybeNumElts = ReadVBR(6); + if (!MaybeNumElts) + return MaybeNumElts.takeError(); + uint32_t NumElts = MaybeNumElts.get(); + + for (unsigned i = 0; i != NumElts; ++i) + if (Expected MaybeVal = ReadVBR64(6)) + Vals.push_back(MaybeVal.get()); + else + return MaybeVal.takeError(); + return Code; + } + + const BitCodeAbbrev *Abbv = getAbbrev(AbbrevID); + + // Read the record code first. + assert(Abbv->getNumOperandInfos() != 0 && "no record code in abbreviation?"); + const BitCodeAbbrevOp &CodeOp = Abbv->getOperandInfo(0); + unsigned Code; + if (CodeOp.isLiteral()) + Code = CodeOp.getLiteralValue(); + else { + if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array || + CodeOp.getEncoding() == BitCodeAbbrevOp::Blob) + report_fatal_error("Abbreviation starts with an Array or a Blob"); + if (Expected MaybeCode = readAbbreviatedField(*this, CodeOp)) + Code = MaybeCode.get(); + else + return MaybeCode.takeError(); + } + + for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) { + const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); + if (Op.isLiteral()) { + Vals.push_back(Op.getLiteralValue()); + continue; + } + + if (Op.getEncoding() != BitCodeAbbrevOp::Array && + Op.getEncoding() != BitCodeAbbrevOp::Blob) { + if (Expected MaybeVal = readAbbreviatedField(*this, Op)) + Vals.push_back(MaybeVal.get()); + else + return MaybeVal.takeError(); + continue; + } + + if (Op.getEncoding() == BitCodeAbbrevOp::Array) { + // Array case. Read the number of elements as a vbr6. + Expected MaybeNumElts = ReadVBR(6); + if (!MaybeNumElts) + return MaybeNumElts.takeError(); + uint32_t NumElts = MaybeNumElts.get(); + + // Get the element encoding. + if (i + 2 != e) + report_fatal_error("Array op not second to last"); + const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i); + if (!EltEnc.isEncoding()) + report_fatal_error( + "Array element type has to be an encoding of a type"); + + // Read all the elements. + switch (EltEnc.getEncoding()) { + default: + report_fatal_error("Array element type can't be an Array or a Blob"); + case BitCodeAbbrevOp::Fixed: + for (; NumElts; --NumElts) + if (Expected MaybeVal = + Read((unsigned)EltEnc.getEncodingData())) + Vals.push_back(MaybeVal.get()); + else + return MaybeVal.takeError(); + break; + case BitCodeAbbrevOp::VBR: + for (; NumElts; --NumElts) + if (Expected MaybeVal = + ReadVBR64((unsigned)EltEnc.getEncodingData())) + Vals.push_back(MaybeVal.get()); + else + return MaybeVal.takeError(); + break; + case BitCodeAbbrevOp::Char6: + for (; NumElts; --NumElts) + if (Expected MaybeVal = Read(6)) + Vals.push_back(BitCodeAbbrevOp::DecodeChar6(MaybeVal.get())); + else + return MaybeVal.takeError(); + } + continue; + } + + assert(Op.getEncoding() == BitCodeAbbrevOp::Blob); + // Blob case. Read the number of bytes as a vbr6. + Expected MaybeNumElts = ReadVBR(6); + if (!MaybeNumElts) + return MaybeNumElts.takeError(); + uint32_t NumElts = MaybeNumElts.get(); + SkipToFourByteBoundary(); // 32-bit alignment + + // Figure out where the end of this blob will be including tail padding. + size_t CurBitPos = GetCurrentBitNo(); + size_t NewEnd = CurBitPos+((NumElts+3)&~3)*8; + + // If this would read off the end of the bitcode file, just set the + // record to empty and return. + if (!canSkipToPos(NewEnd/8)) { + Vals.append(NumElts, 0); + skipToEnd(); + break; + } + + // Otherwise, inform the streamer that we need these bytes in memory. Skip + // over tail padding first, in case jumping to NewEnd invalidates the Blob + // pointer. + if (Error Err = JumpToBit(NewEnd)) + return std::move(Err); + const char *Ptr = (const char *)getPointerToBit(CurBitPos, NumElts); + + // If we can return a reference to the data, do so to avoid copying it. + if (Blob) { + *Blob = StringRef(Ptr, NumElts); + } else { + // Otherwise, unpack into Vals with zero extension. + for (; NumElts; --NumElts) + Vals.push_back((unsigned char)*Ptr++); + } + } + + return Code; +} + +Error BitstreamCursor::ReadAbbrevRecord() { + auto Abbv = std::make_shared(); + Expected MaybeNumOpInfo = ReadVBR(5); + if (!MaybeNumOpInfo) + return MaybeNumOpInfo.takeError(); + unsigned NumOpInfo = MaybeNumOpInfo.get(); + for (unsigned i = 0; i != NumOpInfo; ++i) { + Expected MaybeIsLiteral = Read(1); + if (!MaybeIsLiteral) + return MaybeIsLiteral.takeError(); + bool IsLiteral = MaybeIsLiteral.get(); + if (IsLiteral) { + Expected MaybeOp = ReadVBR64(8); + if (!MaybeOp) + return MaybeOp.takeError(); + Abbv->Add(BitCodeAbbrevOp(MaybeOp.get())); + continue; + } + + Expected MaybeEncoding = Read(3); + if (!MaybeEncoding) + return MaybeEncoding.takeError(); + BitCodeAbbrevOp::Encoding E = + (BitCodeAbbrevOp::Encoding)MaybeEncoding.get(); + if (BitCodeAbbrevOp::hasEncodingData(E)) { + Expected MaybeData = ReadVBR64(5); + if (!MaybeData) + return MaybeData.takeError(); + uint64_t Data = MaybeData.get(); + + // As a special case, handle fixed(0) (i.e., a fixed field with zero bits) + // and vbr(0) as a literal zero. This is decoded the same way, and avoids + // a slow path in Read() to have to handle reading zero bits. + if ((E == BitCodeAbbrevOp::Fixed || E == BitCodeAbbrevOp::VBR) && + Data == 0) { + Abbv->Add(BitCodeAbbrevOp(0)); + continue; + } + + if ((E == BitCodeAbbrevOp::Fixed || E == BitCodeAbbrevOp::VBR) && + Data > MaxChunkSize) + report_fatal_error( + "Fixed or VBR abbrev record with size > MaxChunkData"); + + Abbv->Add(BitCodeAbbrevOp(E, Data)); + } else + Abbv->Add(BitCodeAbbrevOp(E)); + } + + if (Abbv->getNumOperandInfos() == 0) + report_fatal_error("Abbrev record with no operands"); + CurAbbrevs.push_back(std::move(Abbv)); + + return Error::success(); +} + +Expected> +BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) { + if (llvm::Error Err = EnterSubBlock(bitc::BLOCKINFO_BLOCK_ID)) + return std::move(Err); + + BitstreamBlockInfo NewBlockInfo; + + SmallVector Record; + BitstreamBlockInfo::BlockInfo *CurBlockInfo = nullptr; + + // Read all the records for this module. + while (true) { + Expected MaybeEntry = + advanceSkippingSubblocks(AF_DontAutoprocessAbbrevs); + if (!MaybeEntry) + return MaybeEntry.takeError(); + BitstreamEntry Entry = MaybeEntry.get(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + return None; + case llvm::BitstreamEntry::EndBlock: + return std::move(NewBlockInfo); + case llvm::BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read abbrev records, associate them with CurBID. + if (Entry.ID == bitc::DEFINE_ABBREV) { + if (!CurBlockInfo) return None; + if (Error Err = ReadAbbrevRecord()) + return std::move(Err); + + // ReadAbbrevRecord installs the abbrev in CurAbbrevs. Move it to the + // appropriate BlockInfo. + CurBlockInfo->Abbrevs.push_back(std::move(CurAbbrevs.back())); + CurAbbrevs.pop_back(); + continue; + } + + // Read a record. + Record.clear(); + Expected MaybeBlockInfo = readRecord(Entry.ID, Record); + if (!MaybeBlockInfo) + return MaybeBlockInfo.takeError(); + switch (MaybeBlockInfo.get()) { + default: + break; // Default behavior, ignore unknown content. + case bitc::BLOCKINFO_CODE_SETBID: + if (Record.size() < 1) + return None; + CurBlockInfo = &NewBlockInfo.getOrCreateBlockInfo((unsigned)Record[0]); + break; + case bitc::BLOCKINFO_CODE_BLOCKNAME: { + if (!CurBlockInfo) + return None; + if (!ReadBlockInfoNames) + break; // Ignore name. + std::string Name; + for (unsigned i = 0, e = Record.size(); i != e; ++i) + Name += (char)Record[i]; + CurBlockInfo->Name = Name; + break; + } + case bitc::BLOCKINFO_CODE_SETRECORDNAME: { + if (!CurBlockInfo) return None; + if (!ReadBlockInfoNames) + break; // Ignore name. + std::string Name; + for (unsigned i = 1, e = Record.size(); i != e; ++i) + Name += (char)Record[i]; + CurBlockInfo->RecordNames.push_back(std::make_pair((unsigned)Record[0], + Name)); + break; + } + } + } +} Index: llvm/trunk/lib/Bitstream/Reader/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Bitstream/Reader/CMakeLists.txt +++ llvm/trunk/lib/Bitstream/Reader/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(LLVMBitstreamReader + BitstreamReader.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Bitcode + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Bitstream + ) Index: llvm/trunk/lib/Bitstream/Reader/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/Bitstream/Reader/LLVMBuild.txt +++ llvm/trunk/lib/Bitstream/Reader/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./lib/Bitstream/Reader/LLVMBuild.txt ---------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = BitstreamReader +parent = Bitstream +required_libraries = Support Index: llvm/trunk/lib/CMakeLists.txt =================================================================== --- llvm/trunk/lib/CMakeLists.txt +++ llvm/trunk/lib/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(CodeGen) add_subdirectory(BinaryFormat) add_subdirectory(Bitcode) +add_subdirectory(Bitstream) add_subdirectory(Transforms) add_subdirectory(Linker) add_subdirectory(Analysis) Index: llvm/trunk/lib/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/LLVMBuild.txt +++ llvm/trunk/lib/LLVMBuild.txt @@ -19,6 +19,7 @@ Analysis AsmParser Bitcode + Bitstream CodeGen DebugInfo Demangle Index: llvm/trunk/tools/llvm-bcanalyzer/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-bcanalyzer/CMakeLists.txt +++ llvm/trunk/tools/llvm-bcanalyzer/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS BitReader + BitstreamReader Support ) Index: llvm/trunk/tools/llvm-bcanalyzer/LLVMBuild.txt =================================================================== --- llvm/trunk/tools/llvm-bcanalyzer/LLVMBuild.txt +++ llvm/trunk/tools/llvm-bcanalyzer/LLVMBuild.txt @@ -18,4 +18,4 @@ type = Tool name = llvm-bcanalyzer parent = Tools -required_libraries = BitReader +required_libraries = BitReader BitstreamReader Support Index: llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -28,7 +28,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" Index: llvm/trunk/unittests/Bitcode/BitstreamReaderTest.cpp =================================================================== --- llvm/trunk/unittests/Bitcode/BitstreamReaderTest.cpp +++ llvm/trunk/unittests/Bitcode/BitstreamReaderTest.cpp @@ -1,167 +0,0 @@ -//===- BitstreamReaderTest.cpp - Tests for BitstreamReader ----------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Bitcode/BitstreamWriter.h" -#include "gtest/gtest.h" - -using namespace llvm; - -namespace { - -TEST(BitstreamReaderTest, AtEndOfStream) { - uint8_t Bytes[4] = { - 0x00, 0x01, 0x02, 0x03 - }; - BitstreamCursor Cursor(Bytes); - - EXPECT_FALSE(Cursor.AtEndOfStream()); - Expected MaybeRead = Cursor.Read(8); - EXPECT_TRUE((bool)MaybeRead); - EXPECT_FALSE(Cursor.AtEndOfStream()); - MaybeRead = Cursor.Read(24); - EXPECT_TRUE((bool)MaybeRead); - EXPECT_TRUE(Cursor.AtEndOfStream()); - - EXPECT_FALSE(Cursor.JumpToBit(0)); - EXPECT_FALSE(Cursor.AtEndOfStream()); - - EXPECT_FALSE(Cursor.JumpToBit(32)); - EXPECT_TRUE(Cursor.AtEndOfStream()); -} - -TEST(BitstreamReaderTest, AtEndOfStreamJump) { - uint8_t Bytes[4] = { - 0x00, 0x01, 0x02, 0x03 - }; - BitstreamCursor Cursor(Bytes); - - EXPECT_FALSE(Cursor.JumpToBit(32)); - EXPECT_TRUE(Cursor.AtEndOfStream()); -} - -TEST(BitstreamReaderTest, AtEndOfStreamEmpty) { - BitstreamCursor Cursor(ArrayRef{}); - - EXPECT_TRUE(Cursor.AtEndOfStream()); -} - -TEST(BitstreamReaderTest, getCurrentByteNo) { - uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03}; - SimpleBitstreamCursor Cursor(Bytes); - - for (unsigned I = 0, E = 32; I != E; ++I) { - EXPECT_EQ(I / 8, Cursor.getCurrentByteNo()); - Expected MaybeRead = Cursor.Read(1); - EXPECT_TRUE((bool)MaybeRead); - } - EXPECT_EQ(4u, Cursor.getCurrentByteNo()); -} - -TEST(BitstreamReaderTest, getPointerToByte) { - uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - SimpleBitstreamCursor Cursor(Bytes); - - for (unsigned I = 0, E = 8; I != E; ++I) { - EXPECT_EQ(Bytes + I, Cursor.getPointerToByte(I, 1)); - } -} - -TEST(BitstreamReaderTest, getPointerToBit) { - uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - SimpleBitstreamCursor Cursor(Bytes); - - for (unsigned I = 0, E = 8; I != E; ++I) { - EXPECT_EQ(Bytes + I, Cursor.getPointerToBit(I * 8, 1)); - } -} - -TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) { - SmallVector BlobData; - for (unsigned I = 0, E = 1024; I != E; ++I) - BlobData.push_back(I); - - // Try a bunch of different sizes. - const unsigned Magic = 0x12345678; - const unsigned BlockID = bitc::FIRST_APPLICATION_BLOCKID; - const unsigned RecordID = 1; - for (unsigned I = 0, BlobSize = 0, E = BlobData.size(); BlobSize < E; - BlobSize += ++I) { - StringRef BlobIn((const char *)BlobData.begin(), BlobSize); - - // Write the bitcode. - SmallVector Buffer; - unsigned AbbrevID; - { - BitstreamWriter Stream(Buffer); - Stream.Emit(Magic, 32); - Stream.EnterSubblock(BlockID, 3); - - auto Abbrev = std::make_shared(); - Abbrev->Add(BitCodeAbbrevOp(RecordID)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - AbbrevID = Stream.EmitAbbrev(std::move(Abbrev)); - unsigned Record[] = {RecordID}; - Stream.EmitRecordWithBlob(AbbrevID, makeArrayRef(Record), BlobIn); - - Stream.ExitBlock(); - } - - // Stream the buffer into the reader. - BitstreamCursor Stream( - ArrayRef((const uint8_t *)Buffer.begin(), Buffer.size())); - - // Header. Included in test so that we can run llvm-bcanalyzer to debug - // when there are problems. - Expected MaybeRead = Stream.Read(32); - ASSERT_TRUE((bool)MaybeRead); - ASSERT_EQ(Magic, MaybeRead.get()); - - // Block. - Expected MaybeEntry = - Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); - ASSERT_TRUE((bool)MaybeEntry); - BitstreamEntry Entry = MaybeEntry.get(); - ASSERT_EQ(BitstreamEntry::SubBlock, Entry.Kind); - ASSERT_EQ(BlockID, Entry.ID); - ASSERT_FALSE(Stream.EnterSubBlock(BlockID)); - - // Abbreviation. - MaybeEntry = Stream.advance(); - ASSERT_TRUE((bool)MaybeEntry); - Entry = MaybeEntry.get(); - ASSERT_EQ(BitstreamEntry::Record, Entry.Kind); - ASSERT_EQ(AbbrevID, Entry.ID); - - // Record. - StringRef BlobOut; - SmallVector Record; - Expected MaybeRecord = - Stream.readRecord(Entry.ID, Record, &BlobOut); - ASSERT_TRUE((bool)MaybeRecord); - ASSERT_EQ(RecordID, MaybeRecord.get()); - EXPECT_TRUE(Record.empty()); - EXPECT_EQ(BlobIn, BlobOut); - } -} - -TEST(BitstreamReaderTest, shortRead) { - uint8_t Bytes[] = {8, 7, 6, 5, 4, 3, 2, 1}; - for (unsigned I = 1; I != 8; ++I) { - SimpleBitstreamCursor Cursor(ArrayRef(Bytes, I)); - Expected MaybeRead = Cursor.Read(8); - ASSERT_TRUE((bool)MaybeRead); - EXPECT_EQ(8ull, MaybeRead.get()); - } -} - -static_assert(is_trivially_copyable::value, - "trivially copyable"); - -} // end anonymous namespace Index: llvm/trunk/unittests/Bitcode/BitstreamWriterTest.cpp =================================================================== --- llvm/trunk/unittests/Bitcode/BitstreamWriterTest.cpp +++ llvm/trunk/unittests/Bitcode/BitstreamWriterTest.cpp @@ -1,58 +0,0 @@ -//===- BitstreamWriterTest.cpp - Tests for BitstreamWriter ----------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "gtest/gtest.h" - -using namespace llvm; - -namespace { - -TEST(BitstreamWriterTest, emitBlob) { - SmallString<64> Buffer; - BitstreamWriter W(Buffer); - W.emitBlob("str", /* ShouldEmitSize */ false); - EXPECT_EQ(StringRef("str\0", 4), Buffer); -} - -TEST(BitstreamWriterTest, emitBlobWithSize) { - SmallString<64> Buffer; - { - BitstreamWriter W(Buffer); - W.emitBlob("str"); - } - SmallString<64> Expected; - { - BitstreamWriter W(Expected); - W.EmitVBR(3, 6); - W.FlushToWord(); - W.Emit('s', 8); - W.Emit('t', 8); - W.Emit('r', 8); - W.Emit(0, 8); - } - EXPECT_EQ(StringRef(Expected), Buffer); -} - -TEST(BitstreamWriterTest, emitBlobEmpty) { - SmallString<64> Buffer; - BitstreamWriter W(Buffer); - W.emitBlob("", /* ShouldEmitSize */ false); - EXPECT_EQ(StringRef(""), Buffer); -} - -TEST(BitstreamWriterTest, emitBlob4ByteAligned) { - SmallString<64> Buffer; - BitstreamWriter W(Buffer); - W.emitBlob("str0", /* ShouldEmitSize */ false); - EXPECT_EQ(StringRef("str0"), Buffer); -} - -} // end namespace Index: llvm/trunk/unittests/Bitcode/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Bitcode/CMakeLists.txt +++ llvm/trunk/unittests/Bitcode/CMakeLists.txt @@ -8,6 +8,4 @@ add_llvm_unittest(BitcodeTests BitReaderTest.cpp - BitstreamReaderTest.cpp - BitstreamWriterTest.cpp ) Index: llvm/trunk/unittests/Bitstream/BitstreamReaderTest.cpp =================================================================== --- llvm/trunk/unittests/Bitstream/BitstreamReaderTest.cpp +++ llvm/trunk/unittests/Bitstream/BitstreamReaderTest.cpp @@ -0,0 +1,167 @@ +//===- BitstreamReaderTest.cpp - Tests for BitstreamReader ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Bitstream/BitstreamWriter.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(BitstreamReaderTest, AtEndOfStream) { + uint8_t Bytes[4] = { + 0x00, 0x01, 0x02, 0x03 + }; + BitstreamCursor Cursor(Bytes); + + EXPECT_FALSE(Cursor.AtEndOfStream()); + Expected MaybeRead = Cursor.Read(8); + EXPECT_TRUE((bool)MaybeRead); + EXPECT_FALSE(Cursor.AtEndOfStream()); + MaybeRead = Cursor.Read(24); + EXPECT_TRUE((bool)MaybeRead); + EXPECT_TRUE(Cursor.AtEndOfStream()); + + EXPECT_FALSE(Cursor.JumpToBit(0)); + EXPECT_FALSE(Cursor.AtEndOfStream()); + + EXPECT_FALSE(Cursor.JumpToBit(32)); + EXPECT_TRUE(Cursor.AtEndOfStream()); +} + +TEST(BitstreamReaderTest, AtEndOfStreamJump) { + uint8_t Bytes[4] = { + 0x00, 0x01, 0x02, 0x03 + }; + BitstreamCursor Cursor(Bytes); + + EXPECT_FALSE(Cursor.JumpToBit(32)); + EXPECT_TRUE(Cursor.AtEndOfStream()); +} + +TEST(BitstreamReaderTest, AtEndOfStreamEmpty) { + BitstreamCursor Cursor(ArrayRef{}); + + EXPECT_TRUE(Cursor.AtEndOfStream()); +} + +TEST(BitstreamReaderTest, getCurrentByteNo) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03}; + SimpleBitstreamCursor Cursor(Bytes); + + for (unsigned I = 0, E = 32; I != E; ++I) { + EXPECT_EQ(I / 8, Cursor.getCurrentByteNo()); + Expected MaybeRead = Cursor.Read(1); + EXPECT_TRUE((bool)MaybeRead); + } + EXPECT_EQ(4u, Cursor.getCurrentByteNo()); +} + +TEST(BitstreamReaderTest, getPointerToByte) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + SimpleBitstreamCursor Cursor(Bytes); + + for (unsigned I = 0, E = 8; I != E; ++I) { + EXPECT_EQ(Bytes + I, Cursor.getPointerToByte(I, 1)); + } +} + +TEST(BitstreamReaderTest, getPointerToBit) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + SimpleBitstreamCursor Cursor(Bytes); + + for (unsigned I = 0, E = 8; I != E; ++I) { + EXPECT_EQ(Bytes + I, Cursor.getPointerToBit(I * 8, 1)); + } +} + +TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) { + SmallVector BlobData; + for (unsigned I = 0, E = 1024; I != E; ++I) + BlobData.push_back(I); + + // Try a bunch of different sizes. + const unsigned Magic = 0x12345678; + const unsigned BlockID = bitc::FIRST_APPLICATION_BLOCKID; + const unsigned RecordID = 1; + for (unsigned I = 0, BlobSize = 0, E = BlobData.size(); BlobSize < E; + BlobSize += ++I) { + StringRef BlobIn((const char *)BlobData.begin(), BlobSize); + + // Write the bitcode. + SmallVector Buffer; + unsigned AbbrevID; + { + BitstreamWriter Stream(Buffer); + Stream.Emit(Magic, 32); + Stream.EnterSubblock(BlockID, 3); + + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(RecordID)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + AbbrevID = Stream.EmitAbbrev(std::move(Abbrev)); + unsigned Record[] = {RecordID}; + Stream.EmitRecordWithBlob(AbbrevID, makeArrayRef(Record), BlobIn); + + Stream.ExitBlock(); + } + + // Stream the buffer into the reader. + BitstreamCursor Stream( + ArrayRef((const uint8_t *)Buffer.begin(), Buffer.size())); + + // Header. Included in test so that we can run llvm-bcanalyzer to debug + // when there are problems. + Expected MaybeRead = Stream.Read(32); + ASSERT_TRUE((bool)MaybeRead); + ASSERT_EQ(Magic, MaybeRead.get()); + + // Block. + Expected MaybeEntry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + ASSERT_TRUE((bool)MaybeEntry); + BitstreamEntry Entry = MaybeEntry.get(); + ASSERT_EQ(BitstreamEntry::SubBlock, Entry.Kind); + ASSERT_EQ(BlockID, Entry.ID); + ASSERT_FALSE(Stream.EnterSubBlock(BlockID)); + + // Abbreviation. + MaybeEntry = Stream.advance(); + ASSERT_TRUE((bool)MaybeEntry); + Entry = MaybeEntry.get(); + ASSERT_EQ(BitstreamEntry::Record, Entry.Kind); + ASSERT_EQ(AbbrevID, Entry.ID); + + // Record. + StringRef BlobOut; + SmallVector Record; + Expected MaybeRecord = + Stream.readRecord(Entry.ID, Record, &BlobOut); + ASSERT_TRUE((bool)MaybeRecord); + ASSERT_EQ(RecordID, MaybeRecord.get()); + EXPECT_TRUE(Record.empty()); + EXPECT_EQ(BlobIn, BlobOut); + } +} + +TEST(BitstreamReaderTest, shortRead) { + uint8_t Bytes[] = {8, 7, 6, 5, 4, 3, 2, 1}; + for (unsigned I = 1; I != 8; ++I) { + SimpleBitstreamCursor Cursor(ArrayRef(Bytes, I)); + Expected MaybeRead = Cursor.Read(8); + ASSERT_TRUE((bool)MaybeRead); + EXPECT_EQ(8ull, MaybeRead.get()); + } +} + +static_assert(is_trivially_copyable::value, + "trivially copyable"); + +} // end anonymous namespace Index: llvm/trunk/unittests/Bitstream/BitstreamWriterTest.cpp =================================================================== --- llvm/trunk/unittests/Bitstream/BitstreamWriterTest.cpp +++ llvm/trunk/unittests/Bitstream/BitstreamWriterTest.cpp @@ -0,0 +1,58 @@ +//===- BitstreamWriterTest.cpp - Tests for BitstreamWriter ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(BitstreamWriterTest, emitBlob) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.emitBlob("str", /* ShouldEmitSize */ false); + EXPECT_EQ(StringRef("str\0", 4), Buffer); +} + +TEST(BitstreamWriterTest, emitBlobWithSize) { + SmallString<64> Buffer; + { + BitstreamWriter W(Buffer); + W.emitBlob("str"); + } + SmallString<64> Expected; + { + BitstreamWriter W(Expected); + W.EmitVBR(3, 6); + W.FlushToWord(); + W.Emit('s', 8); + W.Emit('t', 8); + W.Emit('r', 8); + W.Emit(0, 8); + } + EXPECT_EQ(StringRef(Expected), Buffer); +} + +TEST(BitstreamWriterTest, emitBlobEmpty) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.emitBlob("", /* ShouldEmitSize */ false); + EXPECT_EQ(StringRef(""), Buffer); +} + +TEST(BitstreamWriterTest, emitBlob4ByteAligned) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.emitBlob("str0", /* ShouldEmitSize */ false); + EXPECT_EQ(StringRef("str0"), Buffer); +} + +} // end namespace Index: llvm/trunk/unittests/Bitstream/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Bitstream/CMakeLists.txt +++ llvm/trunk/unittests/Bitstream/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS + BitstreamReader + ) + +add_llvm_unittest(BitstreamTests + BitstreamReaderTest.cpp + BitstreamWriterTest.cpp + ) Index: llvm/trunk/unittests/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/CMakeLists.txt +++ llvm/trunk/unittests/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(AsmParser) add_subdirectory(BinaryFormat) add_subdirectory(Bitcode) +add_subdirectory(Bitstream) add_subdirectory(CodeGen) add_subdirectory(DebugInfo) add_subdirectory(Demangle) Index: llvm/trunk/utils/GenLibDeps.pl =================================================================== --- llvm/trunk/utils/GenLibDeps.pl +++ llvm/trunk/utils/GenLibDeps.pl @@ -96,6 +96,8 @@ $libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/; $libpath =~ s/^BitReader/Bitcode\/Reader/; $libpath =~ s/^BitWriter/Bitcode\/Writer/; + $libpath =~ s/^BitstreamReader/Bitstream\/Reader/; + $libpath =~ s/^BitstreamWriter/Bitstream\/Writer/; $libpath =~ s/^MSIL/Target\/MSIL/; $libpath =~ s/^Core/IR/; $libpath =~ s/^Instrumentation/Transforms\/Instrumentation/; @@ -136,6 +138,8 @@ $libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/; $libpath =~ s/^BitReader/Bitcode\/Reader/; $libpath =~ s/^BitWriter/Bitcode\/Writer/; + $libpath =~ s/^BitstreamReader/Bitstream\/Reader/; + $libpath =~ s/^BitstreamWriter/Bitstream\/Writer/; $libpath =~ s/^MSIL/Target\/MSIL/; $libpath =~ s/^Core/VMCore/; $libpath =~ s/^Instrumentation/Transforms\/Instrumentation/;