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,8 @@ #define LLVM_BITCODE_READERWRITER_H #include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/ThinLTOInfo.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" @@ -58,6 +60,40 @@ 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. + ErrorOr> getThinLTOIndex( + MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true); + + /// Parse the given function summary and module strings bitcode buffers, + /// returning the ThinLTO index constructed using the given ThinLTO + /// function map. This interface is used in the native object wrapped + /// case, where the function map is constructed from the object's symbol + /// table. If ParseFuncSummary is true, parse the entire function summary into + /// the index, otherwise the summary buffer is ignored and may be empty. + ErrorOr> getThinLTOIndex( + MemoryBufferRef SummaryBuffer, MemoryBufferRef ModStringsBuffer, + std::unique_ptr FuncMap, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true); + + /// Parse the summary information for the given function name into + /// the given index. This is used when we already parsed the rest of + /// the index with getThinLTOIndex and ParseFuncSummary=false. + /// It handles both the bitcode-only and native-object wrapped bitcode + /// cases. + std::error_code readThinLTOFunctionInfo( + 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 +105,21 @@ void WriteBitcodeToFile(const Module *M, raw_ostream &Out, bool ShouldPreserveUseListOrder = false); + // Write the specified module to the given target specific streamer, + // where it will be wrapped in an .llvmbc section. + void WriteModuleToStreamer(const Module *M, MCStreamer &MCS); + + // 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); + + // Write the specified ThinLTO index to the given target specific + // streamer, where it will be wrapped in native object sections. + void WriteThinLTOToStreamer(const ThinLTOFunctionSummaryIndex *Index, + MCStreamer &MCS); + /// 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,77 @@ 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; + // The type of bitcode buffer we are reading, specifically, the bitcode + // block id of the expected outermost ThinLTO block. Default is + // a full THINLTO_BLOCK, which is the bitcode-only file case. + // For native-wrapped bitcode this could be either a THINLTO_SUMMARY_BLOCK + // or a THINLTO_MODULE_STRTAB_BLOCK. + unsigned BufferType = bitc::THINLTO_BLOCK_ID; + // 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, + unsigned BuffType = bitc::THINLTO_BLOCK_ID); + ThinLTOBitcodeReader(LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary = true, + bool CheckPresenceOnly = false, + unsigned BuffType = bitc::THINLTO_BLOCK_ID); + ~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 parseBitcodeInto(std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I); + std::error_code parseFunction(std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I, + size_t FunctionOffset); + + std::error_code parseThinLTOBlock(); + std::error_code parseThinLTOSymtab(); + std::error_code parseThinLTOSummary(); + std::error_code parseThinLTOModuleStringTable(); + +private: + std::error_code parseModule(); + std::error_code parseValueSymbolTable(); + 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, @@ -4622,6 +4694,437 @@ 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, + unsigned BuffType) + : Context(Context), + DiagnosticHandler(getDiagHandler(DiagnosticHandler, Context)), + Buffer(Buffer), + ParseFuncSummaryData(ParseFuncSummary), + CheckThinLTOPresenceOnly(CheckPresenceOnly), + BufferType(BuffType) {} + +ThinLTOBitcodeReader::ThinLTOBitcodeReader(LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary, bool CheckPresenceOnly, + unsigned BuffType) + : Context(Context), + DiagnosticHandler(getDiagHandler(DiagnosticHandler, Context)), + Buffer(nullptr), + ParseFuncSummaryData(ParseFuncSummary), + CheckThinLTOPresenceOnly(CheckPresenceOnly), + BufferType(BuffType) {} + +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. +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; + } + } + } +} + +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::THINLTO_BLOCK_ID: + //errs() << "parseModule found THINLTO_BLOCK_ID\n"; + assert(SeenValueSymbolTable); + SeenThinLTO = true; + if (CheckThinLTOPresenceOnly) { + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseThinLTOBlock()) + return EC; + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + //errs() << "parseModule found VALUE_SYMTAB_BLOCK_ID\n"; + assert(!SeenValueSymbolTable); + SeenValueSymbolTable = true; + if (CheckThinLTOPresenceOnly) { + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseValueSymbolTable()) + return EC; + break; + } + continue; + + case BitstreamEntry::Record: + Stream.skipRecord(Entry.ID); + continue; + } + } +} + +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) { + if (Stream.SkipBlock()) + return error("Invalid record"); + } + else if (std::error_code EC = parseThinLTOSummary()) + 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"); +} + +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. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +std::error_code ThinLTOBitcodeReader::parseThinLTOSummary() { + 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. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +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. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + } + } + llvm_unreachable("Exit infinite loop"); +} + +std::error_code +ThinLTOBitcodeReader::parseBitcodeInto(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 then presumably we are expecting to read a full + // THINLTO_BLOCK from a bitcode-only file. + if (Entry.ID == bitc::MODULE_BLOCK_ID) { + assert (BufferType == bitc::THINLTO_BLOCK_ID); + return parseModule(); + } + + // If we see the summary block first, then presumably we are reading + // the function summary section from a native-object file. + else if (Entry.ID == bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID) { + assert (BufferType == bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID); + if (ParseFuncSummaryData) + return parseThinLTOSummary(); + } + + // If we see the module strtab block first, then presumably we are reading + // the module strtab section from a native-object file. + else if (Entry.ID == bitc::THINLTO_MODULE_STRTAB_BLOCK_ID) { + assert (BufferType == bitc::THINLTO_MODULE_STRTAB_BLOCK_ID); + return parseThinLTOModuleStringTable(); + } + + if (Stream.SkipBlock()) + return error("Invalid record"); + } +} + +// Parse the function information at the given offset in the buffer into +// the index. +std::error_code +ThinLTOBitcodeReader::parseFunction(std::unique_ptr Streamer, + ThinLTOFunctionSummaryIndex *I, + size_t FunctionOffset) { + 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(FunctionOffset); + + 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 { @@ -4743,3 +5246,156 @@ return ""; return Triple.get(); } + +// Parse the given function summary and module strings bitcode buffers, +// returning the ThinLTO index constructed using the given ThinLTO +// function map. This interface is used in the native object wrapped +// case, where the function map is constructed from the object's symbol +// table. If ParseFuncSummary is true, parse the entire function summary into +// the index, otherwise the summary buffer is ignored and may be empty. +ErrorOr> +llvm::getThinLTOIndex(MemoryBufferRef SummaryBuffer, + MemoryBufferRef ModStringsBuffer, + std::unique_ptr FuncMap, + LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary) { + std::unique_ptr SummaryBuf = + MemoryBuffer::getMemBuffer(SummaryBuffer, false); + ThinLTOBitcodeReader *SummaryR = + new ThinLTOBitcodeReader(SummaryBuf.get(), Context, DiagnosticHandler, + ParseFuncSummary, false, + bitc::THINLTO_FUNCTION_SUMMARY_BLOCK_ID); + std::unique_ptr ModStringsBuf = + MemoryBuffer::getMemBuffer(ModStringsBuffer, false); + ThinLTOBitcodeReader *ModStringsR = + new ThinLTOBitcodeReader(ModStringsBuf.get(), Context, DiagnosticHandler, + false, false, + bitc::THINLTO_MODULE_STRTAB_BLOCK_ID); + + std::unique_ptr Index = + llvm::make_unique(); + + Index->setFunctionMap(std::move(*FuncMap)); + + if (std::error_code EC = SummaryR->parseBitcodeInto(nullptr, Index.get())) { + SummaryR->releaseBuffer(); // Never take ownership on error. + return EC; + }; + + if (std::error_code EC = ModStringsR->parseBitcodeInto(nullptr, + Index.get())) { + ModStringsR->releaseBuffer(); // Never take ownership on error. + return EC; + }; + + SummaryBuf.release(); // The ThinLTOBitcodeReader owns it now. + ModStringsBuf.release(); // The ThinLTOBitcodeReader owns it now. + return std::move(Index); +} + +static ErrorOr> +getThinLTOIndexImpl(std::unique_ptr &&Buffer, + LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary) { + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buffer.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->parseBitcodeInto(nullptr, Index.get())) + return cleanupOnError(EC); + + Buffer.release(); // The ThinLTOBitcodeReader owns it now. + return std::move(Index); +} + +// 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. +ErrorOr> +llvm::getThinLTOIndex(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + bool ParseFuncSummary) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + return getThinLTOIndexImpl(std::move(Buf), Context, DiagnosticHandler, + ParseFuncSummary); +} + +static bool hasThinLTOIndexImpl(std::unique_ptr &&Buffer, + LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler) { + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buffer.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->parseBitcodeInto(nullptr, nullptr)) + return cleanupOnError(EC); + + Buffer.release(); // The ThinLTOBitcodeReader owns it now. + return R->foundThinLTO(); +} + +// 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); + return hasThinLTOIndexImpl(std::move(Buf), Context, DiagnosticHandler); +} + +static std::error_code readThinLTOFunctionInfoImpl( + std::unique_ptr &&Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + StringRef FunctionName, + std::unique_ptr Index) { + ThinLTOBitcodeReader *R = + new ThinLTOBitcodeReader(Buffer.get(), Context, DiagnosticHandler); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + return EC; + }; + + // TODO: If we have a FunctionName, then we have the bitcode offset + // of it's summary within the Buffer saved in the ThinLTOFunctionSummary + // entry within the Index's ThinLTOFunctionMap entry for FunctionName. + // Access it and read the record directly. Also, we may have multiple + // entries for the function in the function map's list (e.g. COMDATS), + // so the below will need to be a loop. + size_t FunctionOffset = 0; /* TODO: fill this in. */ + + if (std::error_code EC = R->parseFunction(nullptr, Index.get(), + FunctionOffset)) + return cleanupOnError(EC); + + Buffer.release(); // The ThinLTOBitcodeReader owns it now. + return std::error_code(); +} + +// Parse the summary information for the given function name into +// the given index. This is used when we already parsed the rest of +// the index with getThinLTOIndex and ParseFuncSummary=false. +// It handles both the bitcode-only and native-object wrapped bitcode +// cases. +std::error_code llvm::readThinLTOFunctionInfo( + MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler, + StringRef FunctionName, + std::unique_ptr Index) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + return readThinLTOFunctionInfoImpl(std::move(Buf), Context, DiagnosticHandler, + FunctionName, std::move(Index)); +} Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/Operator.h" #include "llvm/IR/UseListOrder.h" #include "llvm/IR/ValueSymbolTable.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -2348,6 +2349,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) { @@ -2400,6 +2434,13 @@ if (!F->isDeclaration()) WriteFunction(*F, VE, Stream); +#if 0 + // TODO: Put this under the option for generating the per-module + // ThinLTO function index/summary in the compile step. + // Write the ThinLTO info (index will eventually be non-null). + WriteThinLTOBlock(nullptr, Stream); +#endif + Stream.ExitBlock(); } @@ -2508,3 +2549,85 @@ // Write the generated bitstream to "Out". Out.write((char*)&Buffer.front(), Buffer.size()); } + +// TODO: Write Module IR to .llvmbc section. Analagous to WriteBitcodeToFile. +void llvm::WriteModuleToStreamer(const Module *M, MCStreamer &MCS) { +} + +// 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()); +} + +void WriteThinLTOSummaryToStreamer(const ThinLTOFunctionSummaryIndex *Index, + MCStreamer &MCS) { + 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); + + WriteThinLTOSummary(Index, Stream); + + // Emit the generated bitstream to the MCStreamer. + StringRef Str(Buffer.data(), Buffer.size()); + MCS.EmitBytes(Str); +} + +void WriteThinLTOModStringsToStreamer(const ThinLTOFunctionSummaryIndex *Index, + MCStreamer &MCS) { + 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); + + WriteThinLTOModStrings(Index, Stream); + + // Emit the generated bitstream to the MCStreamer. + StringRef Str(Buffer.data(), Buffer.size()); + MCS.EmitBytes(Str); +} + +// Write the specified ThinLTO index to the given target specific +// streamer, where it will be wrapped in native object sections. +void llvm::WriteThinLTOToStreamer(const ThinLTOFunctionSummaryIndex *Index, + MCStreamer &MCS) { + // TODO: ensure symbol table is written to native-wrapped object, and + // that symbol table value is offset into ThinLTO function summary section. + + WriteThinLTOModStringsToStreamer(Index, MCS); + WriteThinLTOSummaryToStreamer(Index, MCS); +} Index: lib/Bitcode/Writer/LLVMBuild.txt =================================================================== --- lib/Bitcode/Writer/LLVMBuild.txt +++ lib/Bitcode/Writer/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = BitWriter parent = Bitcode -required_libraries = Core Support +required_libraries = Core MC Support 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"; } }