Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -42,7 +42,14 @@ TYPE_BLOCK_ID_NEW, - USELIST_BLOCK_ID + USELIST_BLOCK_ID, + + THINLTO_BLOCK_ID, + + // ThinLTO sub-block id's. + THINLTO_SYMTAB_BLOCK_ID, + THINLTO_MODULE_STRTAB_BLOCK_ID, + THINLTO_FUNCTION_SUMMARY_BLOCK_ID }; Index: include/llvm/Bitcode/ReaderWriter.h =================================================================== --- include/llvm/Bitcode/ReaderWriter.h +++ include/llvm/Bitcode/ReaderWriter.h @@ -15,6 +15,7 @@ #define LLVM_BITCODE_READERWRITER_H #include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/ThinLTOInfo.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" @@ -58,6 +59,31 @@ parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, DiagnosticHandlerFunction DiagnosticHandler = nullptr); + /// Check if the given bitcode buffer contains a ThinLTO block. + bool hasThinLTOIndex(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler); + + /// Parse the specified bitcode buffer, returning the ThinLTO index. + /// If ParseFuncSummary is true, parse the entire function summary into + /// the index. Otherwise skip the function summary section, and only create + /// an index object with a map from function name to function summary offset. + /// The index is used to perform lazy function summary reading later. + ErrorOr> getThinLTOIndex( + MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true); + + /// This method supports lazy reading of function summary data from + /// the combined index during function importing. When reading the combined + /// index file, getThinLTOIndex is first invoked with ParseFuncSummary=false. + /// Then this method is called for each function considered for importing, + /// to parse the summary information for the given function name into + /// the index. + std::error_code readThinLTOFunctionSummary( + MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, StringRef FunctionName, + std::unique_ptr Index); + /// \brief Write the specified module to the specified raw output stream. /// /// For streams where it matters, the given stream should be in "binary" @@ -69,6 +95,12 @@ void WriteBitcodeToFile(const Module *M, raw_ostream &Out, bool ShouldPreserveUseListOrder = false); + // Write the specified ThinLTO index to the given raw output stream, + // where it will be written in a new bitcode block. This is used when + // writing the combined index file. + void WriteThinLTOToFile(const ThinLTOFunctionSummaryIndex *Index, + raw_ostream &Out); + /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. /// Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/OperandTraits.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/ThinLTOInfo.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/DataStream.h" #include "llvm/Support/ManagedStatic.h" @@ -376,6 +377,70 @@ Function *F, DenseMap::iterator DeferredFunctionInfoIterator); }; + +// Class to manage readig and parsing ThinLTO bitcode files/sections. +class ThinLTOBitcodeReader { + LLVMContext &Context; + DiagnosticHandlerFunction DiagnosticHandler; + ThinLTOFunctionSummaryIndex *TheIndex = nullptr; + std::unique_ptr Buffer; + std::unique_ptr StreamFile; + BitstreamCursor Stream; + uint64_t NextUnreadBit = 0; + bool SeenValueSymbolTable = false; + bool SeenThinLTO = false; + bool ParseFuncSummaryData = true; + bool CheckThinLTOPresenceOnly = false; + bool BufferContainsFuncSummaryDataOnly = false; + // Map built from the ThinLTO-specific value symbol table parser, + // which holds mapping from the value ID to the name, since the ThinLTO + // symbol table references the value ID for function names. + StringMap ValueSymtab; + +public: + std::error_code error(BitcodeError E, const Twine &Message); + std::error_code error(BitcodeError E); + std::error_code error(const Twine &Message); + + ThinLTOBitcodeReader(MemoryBuffer *Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true, + bool CheckPresenceOnly = false); + ThinLTOBitcodeReader(LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true, + bool CheckPresenceOnly = false); + ~ThinLTOBitcodeReader() { freeState(); } + + void freeState(); + + void releaseBuffer(); + + bool foundThinLTO() { + return SeenThinLTO; + } + + /// \brief Main interface to parsing a bitcode buffer. + /// \returns true if an error occurred. + std::error_code parseSummaryIndexInto(std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I); + + /// \brief Interface for parsing a function summary lazily. + std::error_code parseFunctionSummary(std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I, + size_t FunctionSummaryOffset); + +private: + std::error_code parseModule(); + std::error_code parseValueSymbolTable(); + std::error_code parseThinLTOBlock(); + std::error_code parseThinLTOSymtab(); + std::error_code parseEntireThinLTOSummary(); + std::error_code parseThinLTOModuleStringTable(); + std::error_code initStream(std::unique_ptr Streamer); + std::error_code initStreamFromBuffer(); + std::error_code initLazyStream(std::unique_ptr Streamer); +}; } // namespace BitcodeDiagnosticInfo::BitcodeDiagnosticInfo(std::error_code EC, @@ -4757,6 +4822,442 @@ return std::error_code(); } +std::error_code ThinLTOBitcodeReader::error(BitcodeError E, + const Twine &Message) { + return ::error(DiagnosticHandler, make_error_code(E), Message); +} + +std::error_code ThinLTOBitcodeReader::error(const Twine &Message) { + return ::error(DiagnosticHandler, + make_error_code(BitcodeError::CorruptedBitcode), Message); +} + +std::error_code ThinLTOBitcodeReader::error(BitcodeError E) { + return ::error(DiagnosticHandler, make_error_code(E)); +} + +ThinLTOBitcodeReader::ThinLTOBitcodeReader( + MemoryBuffer *Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary, bool CheckPresenceOnly) + : Context(Context), + DiagnosticHandler(getDiagHandler(DiagnosticHandler, Context)), + Buffer(Buffer), + ParseFuncSummaryData(ParseFuncSummary), + CheckThinLTOPresenceOnly(CheckPresenceOnly) {} + +ThinLTOBitcodeReader::ThinLTOBitcodeReader(LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary, bool CheckPresenceOnly) + : Context(Context), + DiagnosticHandler(getDiagHandler(DiagnosticHandler, Context)), + Buffer(nullptr), + ParseFuncSummaryData(ParseFuncSummary), + CheckThinLTOPresenceOnly(CheckPresenceOnly) {} + +void ThinLTOBitcodeReader::freeState() { + Buffer = nullptr; +} + +void ThinLTOBitcodeReader::releaseBuffer() { Buffer.release(); } + +// Specialized value symbol table parser used when reading ThinLTO +// blocks where we don't actually create global values. This builds a +// map from the value ID to the name, since the ThinLTO symbol table +// references the value ID for function names. +std::error_code ThinLTOBitcodeReader::parseValueSymbolTable() { + if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + + // Read all the records for this value table. + SmallString<128> ValueName; + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). + break; + case bitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N] + if (convertToString(Record, 1, ValueName)) + return error("Invalid record"); + unsigned ValueID = Record[0]; + ValueSymtab.insert(std::make_pair( + StringRef(ValueName.data(), ValueName.size()), ValueID)); + ValueName.clear(); + break; + } + } + } +} + +// Parse just the blocks needed for ThinLTO index building out of the module. +std::error_code ThinLTOBitcodeReader::parseModule() { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return error("Invalid record"); + + // Read the ThinLTO records for this module. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return error("Invalid record"); + break; + case bitc::BLOCKINFO_BLOCK_ID: + // Need to parse these to get abbrev ids (e.g. for VST) + if (Stream.ReadBlockInfoBlock()) + return error("Malformed block"); + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + assert(!SeenValueSymbolTable); + SeenValueSymbolTable = true; + if (CheckThinLTOPresenceOnly) { + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseValueSymbolTable()) + return EC; + break; + case bitc::THINLTO_BLOCK_ID: + assert(SeenValueSymbolTable); + SeenThinLTO = true; + if (CheckThinLTOPresenceOnly) { + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseThinLTOBlock()) + return EC; + break; + } + continue; + + case BitstreamEntry::Record: + Stream.skipRecord(Entry.ID); + continue; + } + } +} + +// This will parse the top level ThinLTO block residing in the module block. +// At the end of this routine the ThinLTO Index is populated with a map +// from function name to ThinLTOFunctionInfo. The function info contains +// either the parsed function summary information (when parsing summaries +// eagerly), or just to the function's offset within the summary section +// if parsing lazily (!ParseFuncSummaryData). +std::error_code ThinLTOBitcodeReader::parseThinLTOBlock() { + if (Stream.EnterSubBlock(bitc::THINLTO_BLOCK_ID)) + return error("Invalid record"); + + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return error("Invalid record"); + break; + case bitc::THINLTO_SYMTAB_BLOCK_ID: + if (std::error_code EC = parseThinLTOSymtab()) + return EC; + break; + case bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID: + if (!ParseFuncSummaryData) { + // Lazy parsing of summary info, skip it. + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseEntireThinLTOSummary()) + return EC; + break; + case bitc::THINLTO_MODULE_STRTAB_BLOCK_ID: + if (std::error_code EC = parseThinLTOModuleStringTable()) + return EC; + break; + } + continue; + + // TODO: Add ThinLTO version number record. + case BitstreamEntry::Record: + return error("Invalid record"); + } + } + llvm_unreachable("Exit infinite loop"); +} + +// Parse the ThinLTO symbol table block which contains the mapping from +// function name (via the VST index) to the function's summary within +// the summary section. +std::error_code ThinLTOBitcodeReader::parseThinLTOSymtab() { + if (Stream.EnterSubBlock(bitc::THINLTO_SYMTAB_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // TODO: Read a record. This will eventually read the records + // containing the function name's VST index and the associated offset within + // the function summary section. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +// Eagerly parse the entire function summary block (i.e. for all functions +// in the index). This populates the ThinLTOFunctionSummary objects in +// the index. +std::error_code ThinLTOBitcodeReader::parseEntireThinLTOSummary() { + if (Stream.EnterSubBlock(bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // TODO: Read a record. This will eventually read records containing + // function summary information for each function, specifically the + // function body's bitcode index, the index into the module string + // table for the bitcode module where it is found, and an evolving + // set of information used to guide function importing decisions. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +// Parse the ThinLTO module string table block into the Index. +// This populates the ModulePathStringTable map in the index. +std::error_code ThinLTOBitcodeReader::parseThinLTOModuleStringTable() { + if (Stream.EnterSubBlock(bitc::THINLTO_MODULE_STRTAB_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // TODO: Read a record. This will eventually add records holding the + // module ID assigned during combined index generation and the associated + // bitcode module path. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +// Parse the ThinLTO index from the bitcode streamer into the given index. +std::error_code +ThinLTOBitcodeReader::parseSummaryIndexInto( + std::unique_ptr Streamer, ThinLTOFunctionSummaryIndex *I) { + TheIndex = I; + + if (std::error_code EC = initStream(std::move(Streamer))) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + if (Stream.AtEndOfStream()) { + // We didn't really read a proper Module block. + return error("Malformed ThihLTO IR file"); + } + + BitstreamEntry Entry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + + if (Entry.Kind != BitstreamEntry::SubBlock) + return error("Malformed block"); + + // If we see a MODULE_BLOCK, parse it to find the THINLTO_BLOCK. + if (Entry.ID == bitc::MODULE_BLOCK_ID) + return parseModule(); + + if (Stream.SkipBlock()) + return error("Invalid record"); + } +} + +// Parse the function information at the given offset in the buffer into +// the index. Used to support lazy parsing of function summaries from the +// combined index during importing. +std::error_code +ThinLTOBitcodeReader::parseFunctionSummary( + std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I, + size_t FunctionSummaryOffset) { + TheIndex = I; + + if (std::error_code EC = initStream(std::move(Streamer))) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return error("Invalid bitcode signature"); + + Stream.JumpToBit(FunctionSummaryOffset); + + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + default: + return error("Malformed block"); + case BitstreamEntry::Record: + // The expected case. + break; + } + + // TODO: Read a record. + SmallVector Record; + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Error, expected to jump to a valid function summary record. + return error("Invalid record"); + } + + return std::error_code(); +} + +std::error_code +ThinLTOBitcodeReader::initStream(std::unique_ptr Streamer) { + if (Streamer) + return initLazyStream(std::move(Streamer)); + return initStreamFromBuffer(); +} + +std::error_code ThinLTOBitcodeReader::initStreamFromBuffer() { + const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart(); + const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); + + if (Buffer->getBufferSize() & 3) + return error("Invalid bitcode signature"); + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) + return error("Invalid bitcode wrapper header"); + + StreamFile.reset(new BitstreamReader(BufPtr, BufEnd)); + Stream.init(&*StreamFile); + + return std::error_code(); +} + +std::error_code +ThinLTOBitcodeReader::initLazyStream(std::unique_ptr Streamer) { + // Check and strip off the bitcode wrapper; BitstreamReader expects never to + // see it. + auto OwnedBytes = + llvm::make_unique(std::move(Streamer)); + StreamingMemoryObject &Bytes = *OwnedBytes; + StreamFile = llvm::make_unique(std::move(OwnedBytes)); + Stream.init(&*StreamFile); + + unsigned char buf[16]; + if (Bytes.readBytes(buf, 16, 0) != 16) + return error("Invalid bitcode signature"); + + if (!isBitcode(buf, buf + 16)) + return error("Invalid bitcode signature"); + + if (isBitcodeWrapper(buf, buf + 4)) { + const unsigned char *bitcodeStart = buf; + const unsigned char *bitcodeEnd = buf + 16; + SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false); + Bytes.dropLeadingBytes(bitcodeStart - buf); + Bytes.setKnownObjectSize(bitcodeEnd - bitcodeStart); + } + return std::error_code(); +} + namespace { class BitcodeErrorCategoryType : public std::error_category { const char *name() const LLVM_NOEXCEPT override { @@ -4878,3 +5379,89 @@ return ""; return Triple.get(); } + +// Parse the specified bitcode buffer, returning the ThinLTO index. +// If ParseFuncSummary is true, parse the entire function summary into +// the index. Otherwise skip the function summary section, and only create +// an index object with a map from function name to function summary offset. +// The index is used to perform lazy function summary reading later. +ErrorOr> +llvm::getThinLTOIndex(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buf.get(), Context, DiagnosticHandler, + ParseFuncSummary); + + std::unique_ptr Index = + llvm::make_unique(); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + return EC; + }; + + if (std::error_code EC = R->parseSummaryIndexInto(nullptr, Index.get())) + return cleanupOnError(EC); + + Buf.release(); // The ThinLTOBitcodeReader owns it now. + return std::move(Index); +} + +// Check if the given bitcode buffer contains a ThinLTO block. +bool llvm::hasThinLTOIndex(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buf.get(), Context, DiagnosticHandler, + false, true); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + return false; + }; + + if (std::error_code EC = R->parseSummaryIndexInto(nullptr, nullptr)) + return cleanupOnError(EC); + + Buf.release(); // The ThinLTOBitcodeReader owns it now. + return R->foundThinLTO(); +} + +// This method supports lazy reading of function summary data from +// the combined index during function importing. When reading the combined +// index file, getThinLTOIndex is first invoked with ParseFuncSummary=false. +// Then this method is called for each function considered for importing, +// to parse the summary information for the given function name into +// the index. +std::error_code llvm::readThinLTOFunctionSummary( + MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + StringRef FunctionName, + std::unique_ptr Index) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buf.get(), Context, DiagnosticHandler); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + return EC; + }; + + // Lookup the given function name in the ThinLTOFunctionMap, which may + // contain a list of function infos in the case of a COMDAT. Walk through + // and parse each function summary info at the function summary offset + // recorded when parsing the ThinLTO symbol table. + ThinLTOFunctionInfoList FuncInfos = Index->getFunctionInfoList(FunctionName); + for (std::vector::iterator FII = FuncInfos.begin(); + FII != FuncInfos.end(); FII++) { + size_t FunctionSummaryOffset = FII->functionSummarySecOffset(); + if (std::error_code EC = R->parseFunctionSummary(nullptr, Index.get(), + FunctionSummaryOffset)) + return cleanupOnError(EC); + } + + Buf.release(); // The ThinLTOBitcodeReader owns it now. + return std::error_code(); +} Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2405,6 +2405,39 @@ Stream.ExitBlock(); } +static void WriteThinLTOModStrings(const ThinLTOFunctionSummaryIndex *I, + BitstreamWriter &Stream) { + Stream.EnterSubblock(bitc::THINLTO_MODULE_STRTAB_BLOCK_ID, 3); + // TODO: Write records + Stream.ExitBlock(); +} + +static void WriteThinLTOSummary(const ThinLTOFunctionSummaryIndex *I, + BitstreamWriter &Stream) { + Stream.EnterSubblock(bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID, 3); + // TODO: Write records + Stream.ExitBlock(); +} + +static void WriteThinLTOSymtab(const ThinLTOFunctionSummaryIndex *I, + BitstreamWriter &Stream) { + Stream.EnterSubblock(bitc::THINLTO_SYMTAB_BLOCK_ID, 3); + // TODO: Write records. We need to have built up a map from function + // name to ValueID saved on the Index before this. + Stream.ExitBlock(); +} + +static void WriteThinLTOBlock(const ThinLTOFunctionSummaryIndex *I, + BitstreamWriter &Stream) { + Stream.EnterSubblock(bitc::THINLTO_BLOCK_ID, 3); + + WriteThinLTOModStrings(I, Stream); + WriteThinLTOSummary(I, Stream); + WriteThinLTOSymtab(I, Stream); + + Stream.ExitBlock(); +} + /// WriteModule - Emit the specified module to the bitstream. static void WriteModule(const Module *M, BitstreamWriter &Stream, bool ShouldPreserveUseListOrder) { @@ -2457,6 +2490,13 @@ if (!F->isDeclaration()) WriteFunction(*F, VE, Stream); + // TODO: Setup/pass non-null index. + // This patch is dependent on patch that adds -fthinlto option and adds/sets + // the EmitThinLTOIndex parameter (http://reviews.llvm.org/D11907). + // Will sync and remove this comment before commit. + if (EmitThinLTOIndex) + WriteThinLTOBlock(nullptr, Stream); + Stream.ExitBlock(); } @@ -2565,3 +2605,26 @@ // Write the generated bitstream to "Out". Out.write((char*)&Buffer.front(), Buffer.size()); } + +// Write the specified ThinLTO index to the given raw output stream, +// where it will be written in a new bitcode block. This is used when +// writing the combined index file. +void llvm::WriteThinLTOToFile(const ThinLTOFunctionSummaryIndex *Index, + raw_ostream &Out) { + SmallVector Buffer; + Buffer.reserve(256*1024); + + BitstreamWriter Stream(Buffer); + + // Emit the bitcode header. + Stream.Emit((unsigned)'B', 8); + Stream.Emit((unsigned)'C', 8); + Stream.Emit(0x0, 4); + Stream.Emit(0xC, 4); + Stream.Emit(0xE, 4); + Stream.Emit(0xD, 4); + + WriteThinLTOBlock(Index, Stream); + + Out.write((char*)&Buffer.front(), Buffer.size()); +} Index: tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -114,6 +114,12 @@ case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; + case bitc::THINLTO_BLOCK_ID: return "THINLTO_BLOCK"; + case bitc::THINLTO_SYMTAB_BLOCK_ID: return "THINLTO_SYMTAB_BLOCK"; + case bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID: + return "THINLTO_FUNCTION_SUMMARY_BLOCK"; + case bitc::THINLTO_MODULE_STRTAB_BLOCK_ID: + return "THINLTO_MODULE_STRTAB_BLOCK"; } }