1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

Bitcode: Add a string table to the bitcode format.

Add a top-level STRTAB block containing a string table blob, and start storing
strings for module codes FUNCTION, GLOBALVAR, ALIAS, IFUNC and COMDAT in
the string table.

This change allows us to share names between globals and comdats as well
as between modules, and improves the efficiency of loading bitcode files by
no longer using a bit encoding for symbol names. Once we start writing the
irsymtab to the bitcode file we will also be able to share strings between
it and the module.

On my machine, link time for Chromium for Linux with ThinLTO decreases by
about 7% for no-op incremental builds or about 1% for full builds. Total
bitcode file size decreases by about 3%.

As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2017-April/111732.html

Differential Revision: https://reviews.llvm.org/D31838

llvm-svn: 300464
This commit is contained in:
Peter Collingbourne 2017-04-17 17:51:36 +00:00
parent 003829fb86
commit 2d3eb26eeb
21 changed files with 674 additions and 439 deletions

View File

@ -550,6 +550,8 @@ LLVM IR is defined with the following blocks:
* 17 --- `TYPE_BLOCK`_ --- This describes all of the types in the module. * 17 --- `TYPE_BLOCK`_ --- This describes all of the types in the module.
* 23 --- `STRTAB_BLOCK`_ --- The bitcode file's string table.
.. _MODULE_BLOCK: .. _MODULE_BLOCK:
MODULE_BLOCK Contents MODULE_BLOCK Contents
@ -577,7 +579,7 @@ MODULE_CODE_VERSION Record
``[VERSION, version#]`` ``[VERSION, version#]``
The ``VERSION`` record (code 1) contains a single value indicating the format The ``VERSION`` record (code 1) contains a single value indicating the format
version. Versions 0 and 1 are supported at this time. The difference between version. Versions 0, 1 and 2 are supported at this time. The difference between
version 0 and 1 is in the encoding of instruction operands in version 0 and 1 is in the encoding of instruction operands in
each `FUNCTION_BLOCK`_. each `FUNCTION_BLOCK`_.
@ -620,6 +622,12 @@ as unsigned VBRs. However, forward references are rare, except in the
case of phi instructions. For phi instructions, operands are encoded as case of phi instructions. For phi instructions, operands are encoded as
`Signed VBRs`_ to deal with forward references. `Signed VBRs`_ to deal with forward references.
In version 2, the meaning of module records ``FUNCTION``, ``GLOBALVAR``,
``ALIAS``, ``IFUNC`` and ``COMDAT`` change such that the first two operands
specify an offset and size of a string in a string table (see `STRTAB_BLOCK
Contents`_), the function name is removed from the ``FNENTRY`` record in the
value symbol table, and the top-level ``VALUE_SYMTAB_BLOCK`` may only contain
``FNENTRY`` records.
MODULE_CODE_TRIPLE Record MODULE_CODE_TRIPLE Record
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -673,11 +681,14 @@ for each library name referenced.
MODULE_CODE_GLOBALVAR Record MODULE_CODE_GLOBALVAR Record
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``[GLOBALVAR, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr, externally_initialized, dllstorageclass, comdat]`` ``[GLOBALVAR, strtab offset, strtab size, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr, externally_initialized, dllstorageclass, comdat]``
The ``GLOBALVAR`` record (code 7) marks the declaration or definition of a The ``GLOBALVAR`` record (code 7) marks the declaration or definition of a
global variable. The operand fields are: global variable. The operand fields are:
* *strtab offset*, *strtab size*: Specifies the name of the global variable.
See `STRTAB_BLOCK Contents`_.
* *pointer type*: The type index of the pointer type used to point to this * *pointer type*: The type index of the pointer type used to point to this
global variable global variable
@ -755,11 +766,14 @@ global variable. The operand fields are:
MODULE_CODE_FUNCTION Record MODULE_CODE_FUNCTION Record
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
``[FUNCTION, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata, personalityfn]`` ``[FUNCTION, strtab offset, strtab size, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata, personalityfn]``
The ``FUNCTION`` record (code 8) marks the declaration or definition of a The ``FUNCTION`` record (code 8) marks the declaration or definition of a
function. The operand fields are: function. The operand fields are:
* *strtab offset*, *strtab size*: Specifies the name of the function.
See `STRTAB_BLOCK Contents`_.
* *type*: The type index of the function type describing this function * *type*: The type index of the function type describing this function
* *callingconv*: The calling convention number: * *callingconv*: The calling convention number:
@ -817,11 +831,14 @@ function. The operand fields are:
MODULE_CODE_ALIAS Record MODULE_CODE_ALIAS Record
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
``[ALIAS, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr]`` ``[ALIAS, strtab offset, strtab size, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr]``
The ``ALIAS`` record (code 9) marks the definition of an alias. The operand The ``ALIAS`` record (code 9) marks the definition of an alias. The operand
fields are fields are
* *strtab offset*, *strtab size*: Specifies the name of the alias.
See `STRTAB_BLOCK Contents`_.
* *alias type*: The type index of the alias * *alias type*: The type index of the alias
* *aliasee val#*: The value index of the aliased value * *aliasee val#*: The value index of the aliased value
@ -1300,3 +1317,20 @@ METADATA_ATTACHMENT Contents
---------------------------- ----------------------------
The ``METADATA_ATTACHMENT`` block (id 16) ... The ``METADATA_ATTACHMENT`` block (id 16) ...
.. _STRTAB_BLOCK:
STRTAB_BLOCK Contents
---------------------
The ``STRTAB`` block (id 23) contains a single record (``STRTAB_BLOB``, id 1)
with a single blob operand containing the bitcode file's string table.
Strings in the string table are not null terminated. A record's *strtab
offset* and *strtab size* operands specify the byte offset and size of a
string within the string table.
The string table is used by all preceding blocks in the bitcode file that are
not succeeded by another intervening ``STRTAB`` block. Normally a bitcode
file will have a single string table, but it may have more than one if it
was created by binary concatenation of multiple bitcode files.

View File

@ -46,6 +46,9 @@ namespace llvm {
ArrayRef<uint8_t> Buffer; ArrayRef<uint8_t> Buffer;
StringRef ModuleIdentifier; StringRef ModuleIdentifier;
// The string table used to interpret this module.
StringRef Strtab;
// The bitstream location of the IDENTIFICATION_BLOCK. // The bitstream location of the IDENTIFICATION_BLOCK.
uint64_t IdentificationBit; uint64_t IdentificationBit;
@ -70,6 +73,7 @@ namespace llvm {
StringRef getBuffer() const { StringRef getBuffer() const {
return StringRef((const char *)Buffer.begin(), Buffer.size()); return StringRef((const char *)Buffer.begin(), Buffer.size());
} }
StringRef getStrtab() const { return Strtab; }
StringRef getModuleIdentifier() const { return ModuleIdentifier; } StringRef getModuleIdentifier() const { return ModuleIdentifier; }

View File

@ -15,6 +15,7 @@
#define LLVM_BITCODE_BITCODEWRITER_H #define LLVM_BITCODE_BITCODEWRITER_H
#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/MC/StringTableBuilder.h"
#include <string> #include <string>
namespace llvm { namespace llvm {
@ -26,12 +27,25 @@ namespace llvm {
SmallVectorImpl<char> &Buffer; SmallVectorImpl<char> &Buffer;
std::unique_ptr<BitstreamWriter> Stream; std::unique_ptr<BitstreamWriter> Stream;
StringTableBuilder StrtabBuilder{StringTableBuilder::RAW};
bool WroteStrtab = false;
void writeBlob(unsigned Block, unsigned Record, StringRef Blob);
public: public:
/// Create a BitcodeWriter that writes to Buffer. /// Create a BitcodeWriter that writes to Buffer.
BitcodeWriter(SmallVectorImpl<char> &Buffer); BitcodeWriter(SmallVectorImpl<char> &Buffer);
~BitcodeWriter(); ~BitcodeWriter();
/// Write the bitcode file's string table. This must be called exactly once
/// after all modules have been written.
void writeStrtab();
/// Copy the string table for another module into this bitcode file. This
/// should be called after copying the module itself into the bitcode file.
void copyStrtab(StringRef Strtab);
/// Write the specified module to the buffer specified at construction time. /// Write the specified module to the buffer specified at construction time.
/// ///
/// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a /// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a

View File

@ -22,7 +22,7 @@
namespace llvm { namespace llvm {
namespace bitc { namespace bitc {
// The only top-level block type defined is for a module. // The only top-level block types are MODULE, IDENTIFICATION and STRTAB.
enum BlockIDs { enum BlockIDs {
// Blocks // Blocks
MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID, MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID,
@ -52,7 +52,9 @@ enum BlockIDs {
OPERAND_BUNDLE_TAGS_BLOCK_ID, OPERAND_BUNDLE_TAGS_BLOCK_ID,
METADATA_KIND_BLOCK_ID METADATA_KIND_BLOCK_ID,
STRTAB_BLOCK_ID,
}; };
/// Identification block contains a string that describes the producer details, /// Identification block contains a string that describes the producer details,
@ -232,6 +234,10 @@ enum GlobalValueSummarySymtabCodes {
// llvm.type.checked.load intrinsic with all constant integer arguments. // llvm.type.checked.load intrinsic with all constant integer arguments.
// [typeid, offset, n x arg] // [typeid, offset, n x arg]
FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15, FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15,
// Assigns a GUID to a value ID. This normally appears only in combined
// summaries, but it can also appear in per-module summaries for PGO data.
// [valueid, guid]
FS_VALUE_GUID = 16,
}; };
enum MetadataCodes { enum MetadataCodes {
@ -550,6 +556,10 @@ enum ComdatSelectionKindCodes {
COMDAT_SELECTION_KIND_SAME_SIZE = 5, COMDAT_SELECTION_KIND_SAME_SIZE = 5,
}; };
enum StrtabCodes {
STRTAB_BLOB = 1,
};
} // End bitc namespace } // End bitc namespace
} // End llvm namespace } // End llvm namespace

View File

@ -372,15 +372,27 @@ Expected<std::string> readTriple(BitstreamCursor &Stream) {
class BitcodeReaderBase { class BitcodeReaderBase {
protected: protected:
BitcodeReaderBase(BitstreamCursor Stream) : Stream(std::move(Stream)) { BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab)
: Stream(std::move(Stream)), Strtab(Strtab) {
this->Stream.setBlockInfo(&BlockInfo); this->Stream.setBlockInfo(&BlockInfo);
} }
BitstreamBlockInfo BlockInfo; BitstreamBlockInfo BlockInfo;
BitstreamCursor Stream; BitstreamCursor Stream;
StringRef Strtab;
/// In version 2 of the bitcode we store names of global values and comdats in
/// a string table rather than in the VST.
bool UseStrtab = false;
Expected<unsigned> parseVersionRecord(ArrayRef<uint64_t> Record); Expected<unsigned> parseVersionRecord(ArrayRef<uint64_t> Record);
/// If this module uses a string table, pop the reference to the string table
/// and return the referenced string and the rest of the record. Otherwise
/// just return the record itself.
std::pair<StringRef, ArrayRef<uint64_t>>
readNameFromStrtab(ArrayRef<uint64_t> Record);
bool readBlockInfo(); bool readBlockInfo();
// Contains an arbitrary and optional string identifying the bitcode producer // Contains an arbitrary and optional string identifying the bitcode producer
@ -402,11 +414,22 @@ BitcodeReaderBase::parseVersionRecord(ArrayRef<uint64_t> Record) {
if (Record.size() < 1) if (Record.size() < 1)
return error("Invalid record"); return error("Invalid record");
unsigned ModuleVersion = Record[0]; unsigned ModuleVersion = Record[0];
if (ModuleVersion > 1) if (ModuleVersion > 2)
return error("Invalid value"); return error("Invalid value");
UseStrtab = ModuleVersion >= 2;
return ModuleVersion; return ModuleVersion;
} }
std::pair<StringRef, ArrayRef<uint64_t>>
BitcodeReaderBase::readNameFromStrtab(ArrayRef<uint64_t> Record) {
if (!UseStrtab)
return {"", Record};
// Invalid reference. Let the caller complain about the record being empty.
if (Record[0] + Record[1] > Strtab.size())
return {"", {}};
return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)};
}
class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
LLVMContext &Context; LLVMContext &Context;
Module *TheModule = nullptr; Module *TheModule = nullptr;
@ -492,8 +515,8 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
std::vector<std::string> BundleTags; std::vector<std::string> BundleTags;
public: public:
BitcodeReader(BitstreamCursor Stream, StringRef ProducerIdentification, BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
LLVMContext &Context); StringRef ProducerIdentification, LLVMContext &Context);
Error materializeForwardReferencedFunctions(); Error materializeForwardReferencedFunctions();
@ -628,7 +651,10 @@ private:
Expected<Value *> recordValue(SmallVectorImpl<uint64_t> &Record, Expected<Value *> recordValue(SmallVectorImpl<uint64_t> &Record,
unsigned NameIndex, Triple &TT); unsigned NameIndex, Triple &TT);
void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F,
ArrayRef<uint64_t> Record);
Error parseValueSymbolTable(uint64_t Offset = 0); Error parseValueSymbolTable(uint64_t Offset = 0);
Error parseGlobalValueSymbolTable();
Error parseConstants(); Error parseConstants();
Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBodies();
Error rememberAndSkipFunctionBody(); Error rememberAndSkipFunctionBody();
@ -681,12 +707,15 @@ class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase {
std::string SourceFileName; std::string SourceFileName;
public: public:
ModuleSummaryIndexBitcodeReader( ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab,
BitstreamCursor Stream, ModuleSummaryIndex &TheIndex); ModuleSummaryIndex &TheIndex);
Error parseModule(StringRef ModulePath); Error parseModule(StringRef ModulePath);
private: private:
void setValueGUID(uint64_t ValueID, StringRef ValueName,
GlobalValue::LinkageTypes Linkage,
StringRef SourceFileName);
Error parseValueSymbolTable( Error parseValueSymbolTable(
uint64_t Offset, uint64_t Offset,
DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap); DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap);
@ -716,10 +745,10 @@ std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx,
return std::error_code(); return std::error_code();
} }
BitcodeReader::BitcodeReader(BitstreamCursor Stream, BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
StringRef ProducerIdentification, StringRef ProducerIdentification,
LLVMContext &Context) LLVMContext &Context)
: BitcodeReaderBase(std::move(Stream)), Context(Context), : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context),
ValueList(Context) { ValueList(Context) {
this->ProducerIdentification = ProducerIdentification; this->ProducerIdentification = ProducerIdentification;
} }
@ -1749,6 +1778,54 @@ static uint64_t jumpToValueSymbolTable(uint64_t Offset,
return CurrentBit; return CurrentBit;
} }
void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta,
Function *F,
ArrayRef<uint64_t> Record) {
// Note that we subtract 1 here because the offset is relative to one word
// before the start of the identification or module block, which was
// historically always the start of the regular bitcode header.
uint64_t FuncWordOffset = Record[1] - 1;
uint64_t FuncBitOffset = FuncWordOffset * 32;
DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta;
// Set the LastFunctionBlockBit to point to the last function block.
// Later when parsing is resumed after function materialization,
// we can simply skip that last function block.
if (FuncBitOffset > LastFunctionBlockBit)
LastFunctionBlockBit = FuncBitOffset;
}
/// Read a new-style GlobalValue symbol table.
Error BitcodeReader::parseGlobalValueSymbolTable() {
unsigned FuncBitcodeOffsetDelta =
Stream.getAbbrevIDWidth() + bitc::BlockIDWidth;
if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID))
return error("Invalid record");
SmallVector<uint64_t, 64> Record;
while (true) {
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
switch (Entry.Kind) {
case BitstreamEntry::SubBlock:
case BitstreamEntry::Error:
return error("Malformed block");
case BitstreamEntry::EndBlock:
return Error::success();
case BitstreamEntry::Record:
break;
}
Record.clear();
switch (Stream.readRecord(Entry.ID, Record)) {
case bitc::VST_CODE_FNENTRY: // [valueid, offset]
setDeferredFunctionInfo(FuncBitcodeOffsetDelta,
cast<Function>(ValueList[Record[0]]), Record);
break;
}
}
}
/// Parse the value symbol table at either the current parsing location or /// Parse the value symbol table at either the current parsing location or
/// at the given bit offset if provided. /// at the given bit offset if provided.
Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
@ -1756,8 +1833,18 @@ Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
// Pass in the Offset to distinguish between calling for the module-level // Pass in the Offset to distinguish between calling for the module-level
// VST (where we want to jump to the VST offset) and the function-level // VST (where we want to jump to the VST offset) and the function-level
// VST (where we don't). // VST (where we don't).
if (Offset > 0) if (Offset > 0) {
CurrentBit = jumpToValueSymbolTable(Offset, Stream); CurrentBit = jumpToValueSymbolTable(Offset, Stream);
// If this module uses a string table, read this as a module-level VST.
if (UseStrtab) {
if (Error Err = parseGlobalValueSymbolTable())
return Err;
Stream.JumpToBit(CurrentBit);
return Error::success();
}
// Otherwise, the VST will be in a similar format to a function-level VST,
// and will contain symbol names.
}
// Compute the delta between the bitcode indices in the VST (the word offset // Compute the delta between the bitcode indices in the VST (the word offset
// to the word-aligned ENTER_SUBBLOCK for the function block, and that // to the word-aligned ENTER_SUBBLOCK for the function block, and that
@ -1818,23 +1905,10 @@ Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
return Err; return Err;
Value *V = ValOrErr.get(); Value *V = ValOrErr.get();
auto *F = dyn_cast<Function>(V);
// Ignore function offsets emitted for aliases of functions in older // Ignore function offsets emitted for aliases of functions in older
// versions of LLVM. // versions of LLVM.
if (!F) if (auto *F = dyn_cast<Function>(V))
break; setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record);
// Note that we subtract 1 here because the offset is relative to one word
// before the start of the identification or module block, which was
// historically always the start of the regular bitcode header.
uint64_t FuncWordOffset = Record[1] - 1;
uint64_t FuncBitOffset = FuncWordOffset * 32;
DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta;
// Set the LastFunctionBlockBit to point to the last function block.
// Later when parsing is resumed after function materialization,
// we can simply skip that last function block.
if (FuncBitOffset > LastFunctionBlockBit)
LastFunctionBlockBit = FuncBitOffset;
break; break;
} }
case bitc::VST_CODE_BBENTRY: { case bitc::VST_CODE_BBENTRY: {
@ -2626,15 +2700,24 @@ bool BitcodeReaderBase::readBlockInfo() {
} }
Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) { Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
// [selection_kind, name] // v1: [selection_kind, name]
if (Record.size() < 2) // v2: [strtab_offset, strtab_size, selection_kind]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
if (Record.size() < 1)
return error("Invalid record"); return error("Invalid record");
Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]);
std::string Name; std::string OldFormatName;
unsigned ComdatNameSize = Record[1]; if (!UseStrtab) {
Name.reserve(ComdatNameSize); if (Record.size() < 2)
for (unsigned i = 0; i != ComdatNameSize; ++i) return error("Invalid record");
Name += (char)Record[2 + i]; unsigned ComdatNameSize = Record[1];
OldFormatName.reserve(ComdatNameSize);
for (unsigned i = 0; i != ComdatNameSize; ++i)
OldFormatName += (char)Record[2 + i];
Name = OldFormatName;
}
Comdat *C = TheModule->getOrInsertComdat(Name); Comdat *C = TheModule->getOrInsertComdat(Name);
C->setSelectionKind(SK); C->setSelectionKind(SK);
ComdatList.push_back(C); ComdatList.push_back(C);
@ -2642,9 +2725,13 @@ Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
} }
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) { Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
// [pointer type, isconst, initid, linkage, alignment, section, // v1: [pointer type, isconst, initid, linkage, alignment, section,
// visibility, threadlocal, unnamed_addr, externally_initialized, // visibility, threadlocal, unnamed_addr, externally_initialized,
// dllstorageclass, comdat] // dllstorageclass, comdat] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
if (Record.size() < 6) if (Record.size() < 6)
return error("Invalid record"); return error("Invalid record");
Type *Ty = getTypeByID(Record[0]); Type *Ty = getTypeByID(Record[0]);
@ -2692,7 +2779,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
ExternallyInitialized = Record[9]; ExternallyInitialized = Record[9];
GlobalVariable *NewGV = GlobalVariable *NewGV =
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name,
nullptr, TLM, AddressSpace, ExternallyInitialized); nullptr, TLM, AddressSpace, ExternallyInitialized);
NewGV->setAlignment(Alignment); NewGV->setAlignment(Alignment);
if (!Section.empty()) if (!Section.empty())
@ -2724,9 +2811,13 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
} }
Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) { Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
// [type, callingconv, isproto, linkage, paramattr, alignment, section, // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat,
// prefixdata] // prefixdata] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
if (Record.size() < 8) if (Record.size() < 8)
return error("Invalid record"); return error("Invalid record");
Type *Ty = getTypeByID(Record[0]); Type *Ty = getTypeByID(Record[0]);
@ -2742,7 +2833,7 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
return error("Invalid calling convention ID"); return error("Invalid calling convention ID");
Function *Func = Function *Func =
Function::Create(FTy, GlobalValue::ExternalLinkage, "", TheModule); Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule);
Func->setCallingConv(CC); Func->setCallingConv(CC);
bool isProto = Record[2]; bool isProto = Record[2];
@ -2810,11 +2901,15 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
Error BitcodeReader::parseGlobalIndirectSymbolRecord( Error BitcodeReader::parseGlobalIndirectSymbolRecord(
unsigned BitCode, ArrayRef<uint64_t> Record) { unsigned BitCode, ArrayRef<uint64_t> Record) {
// ALIAS_OLD: [alias type, aliasee val#, linkage] // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST)
// ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
// dllstorageclass] // dllstorageclass] (name in VST)
// IFUNC: [alias type, addrspace, aliasee val#, linkage, // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage,
// visibility, dllstorageclass] // visibility, dllstorageclass] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD;
if (Record.size() < (3 + (unsigned)NewRecord)) if (Record.size() < (3 + (unsigned)NewRecord))
return error("Invalid record"); return error("Invalid record");
@ -2839,10 +2934,10 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
GlobalIndirectSymbol *NewGA; GlobalIndirectSymbol *NewGA;
if (BitCode == bitc::MODULE_CODE_ALIAS || if (BitCode == bitc::MODULE_CODE_ALIAS ||
BitCode == bitc::MODULE_CODE_ALIAS_OLD) BitCode == bitc::MODULE_CODE_ALIAS_OLD)
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "", NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
TheModule); TheModule);
else else
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "", NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
nullptr, TheModule); nullptr, TheModule);
// Old bitcode files didn't have visibility field. // Old bitcode files didn't have visibility field.
// Local linkage must have default visibility. // Local linkage must have default visibility.
@ -4570,8 +4665,8 @@ std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const {
} }
ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader(
BitstreamCursor Cursor, ModuleSummaryIndex &TheIndex) BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex)
: BitcodeReaderBase(std::move(Cursor)), TheIndex(TheIndex) {} : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex) {}
std::pair<GlobalValue::GUID, GlobalValue::GUID> std::pair<GlobalValue::GUID, GlobalValue::GUID>
ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) { ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
@ -4580,12 +4675,32 @@ ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
return VGI->second; return VGI->second;
} }
void ModuleSummaryIndexBitcodeReader::setValueGUID(
uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage,
StringRef SourceFileName) {
std::string GlobalId =
GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName);
auto ValueGUID = GlobalValue::getGUID(GlobalId);
auto OriginalNameID = ValueGUID;
if (GlobalValue::isLocalLinkage(Linkage))
OriginalNameID = GlobalValue::getGUID(ValueName);
if (PrintSummaryGUIDs)
dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is "
<< ValueName << "\n";
ValueIdToCallGraphGUIDMap[ValueID] =
std::make_pair(ValueGUID, OriginalNameID);
}
// Specialized value symbol table parser used when reading module index // Specialized value symbol table parser used when reading module index
// blocks where we don't actually create global values. The parsed information // blocks where we don't actually create global values. The parsed information
// is saved in the bitcode reader for use when later parsing summaries. // is saved in the bitcode reader for use when later parsing summaries.
Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
uint64_t Offset, uint64_t Offset,
DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap) { DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap) {
// With a strtab the VST is not required to parse the summary.
if (UseStrtab)
return Error::success();
assert(Offset > 0 && "Expected non-zero VST offset"); assert(Offset > 0 && "Expected non-zero VST offset");
uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream); uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream);
@ -4627,17 +4742,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
assert(VLI != ValueIdToLinkageMap.end() && assert(VLI != ValueIdToLinkageMap.end() &&
"No linkage found for VST entry?"); "No linkage found for VST entry?");
auto Linkage = VLI->second; auto Linkage = VLI->second;
std::string GlobalId = setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName);
auto ValueGUID = GlobalValue::getGUID(GlobalId);
auto OriginalNameID = ValueGUID;
if (GlobalValue::isLocalLinkage(Linkage))
OriginalNameID = GlobalValue::getGUID(ValueName);
if (PrintSummaryGUIDs)
dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is "
<< ValueName << "\n";
ValueIdToCallGraphGUIDMap[ValueID] =
std::make_pair(ValueGUID, OriginalNameID);
ValueName.clear(); ValueName.clear();
break; break;
} }
@ -4651,18 +4756,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
assert(VLI != ValueIdToLinkageMap.end() && assert(VLI != ValueIdToLinkageMap.end() &&
"No linkage found for VST entry?"); "No linkage found for VST entry?");
auto Linkage = VLI->second; auto Linkage = VLI->second;
std::string FunctionGlobalId = GlobalValue::getGlobalIdentifier( setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
ValueName, VLI->second, SourceFileName);
auto FunctionGUID = GlobalValue::getGUID(FunctionGlobalId);
auto OriginalNameID = FunctionGUID;
if (GlobalValue::isLocalLinkage(Linkage))
OriginalNameID = GlobalValue::getGUID(ValueName);
if (PrintSummaryGUIDs)
dbgs() << "GUID " << FunctionGUID << "(" << OriginalNameID << ") is "
<< ValueName << "\n";
ValueIdToCallGraphGUIDMap[ValueID] =
std::make_pair(FunctionGUID, OriginalNameID);
ValueName.clear(); ValueName.clear();
break; break;
} }
@ -4749,6 +4843,11 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
switch (BitCode) { switch (BitCode) {
default: default:
break; // Default behavior, ignore unknown content. break; // Default behavior, ignore unknown content.
case bitc::MODULE_CODE_VERSION: {
if (Error Err = parseVersionRecord(Record).takeError())
return Err;
break;
}
/// MODULE_CODE_SOURCE_FILENAME: [namechar x N] /// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
case bitc::MODULE_CODE_SOURCE_FILENAME: { case bitc::MODULE_CODE_SOURCE_FILENAME: {
SmallString<128> ValueName; SmallString<128> ValueName;
@ -4783,17 +4882,26 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
// was historically always the start of the regular bitcode header. // was historically always the start of the regular bitcode header.
VSTOffset = Record[0] - 1; VSTOffset = Record[0] - 1;
break; break;
// GLOBALVAR: [pointer type, isconst, initid, linkage, ...] // v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...]
// FUNCTION: [type, callingconv, isproto, linkage, ...] // v1 FUNCTION: [type, callingconv, isproto, linkage, ...]
// ALIAS: [alias type, addrspace, aliasee val#, linkage, ...] // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...]
// v2: [strtab offset, strtab size, v1]
case bitc::MODULE_CODE_GLOBALVAR: case bitc::MODULE_CODE_GLOBALVAR:
case bitc::MODULE_CODE_FUNCTION: case bitc::MODULE_CODE_FUNCTION:
case bitc::MODULE_CODE_ALIAS: { case bitc::MODULE_CODE_ALIAS: {
if (Record.size() <= 3) StringRef Name;
ArrayRef<uint64_t> GVRecord;
std::tie(Name, GVRecord) = readNameFromStrtab(Record);
if (GVRecord.size() <= 3)
return error("Invalid record"); return error("Invalid record");
uint64_t RawLinkage = Record[3]; uint64_t RawLinkage = GVRecord[3];
GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
ValueIdToLinkageMap[ValueId++] = Linkage; if (!UseStrtab) {
ValueIdToLinkageMap[ValueId++] = Linkage;
break;
}
setValueGUID(ValueId++, Name, Linkage, SourceFileName);
break; break;
} }
} }
@ -4904,6 +5012,12 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(
switch (BitCode) { switch (BitCode) {
default: // Default behavior: ignore. default: // Default behavior: ignore.
break; break;
case bitc::FS_VALUE_GUID: { // [valueid, refguid]
uint64_t ValueID = Record[0];
GlobalValue::GUID RefGUID = Record[1];
ValueIdToCallGraphGUIDMap[ValueID] = std::make_pair(RefGUID, RefGUID);
break;
}
// FS_PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid, // FS_PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid,
// n x (valueid)] // n x (valueid)]
// FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs, // FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs,
@ -5208,6 +5322,35 @@ const std::error_category &llvm::BitcodeErrorCategory() {
return *ErrorCategory; return *ErrorCategory;
} }
static Expected<StringRef> readStrtab(BitstreamCursor &Stream) {
if (Stream.EnterSubBlock(bitc::STRTAB_BLOCK_ID))
return error("Invalid record");
StringRef Strtab;
while (1) {
BitstreamEntry Entry = Stream.advance();
switch (Entry.Kind) {
case BitstreamEntry::EndBlock:
return Strtab;
case BitstreamEntry::Error:
return error("Malformed block");
case BitstreamEntry::SubBlock:
if (Stream.SkipBlock())
return error("Malformed block");
break;
case BitstreamEntry::Record:
StringRef Blob;
SmallVector<uint64_t, 1> Record;
if (Stream.readRecord(Entry.ID, Record, &Blob) == bitc::STRTAB_BLOB)
Strtab = Blob;
break;
}
}
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// External interface // External interface
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -5260,6 +5403,22 @@ llvm::getBitcodeModuleList(MemoryBufferRef Buffer) {
continue; continue;
} }
if (Entry.ID == bitc::STRTAB_BLOCK_ID) {
Expected<StringRef> Strtab = readStrtab(Stream);
if (!Strtab)
return Strtab.takeError();
// This string table is used by every preceding bitcode module that does
// not have its own string table. A bitcode file may have multiple
// string tables if it was created by binary concatenation, for example
// with "llvm-cat -b".
for (auto I = Modules.rbegin(), E = Modules.rend(); I != E; ++I) {
if (!I->Strtab.empty())
break;
I->Strtab = *Strtab;
}
continue;
}
if (Stream.SkipBlock()) if (Stream.SkipBlock())
return error("Malformed block"); return error("Malformed block");
continue; continue;
@ -5296,8 +5455,8 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
} }
Stream.JumpToBit(ModuleBit); Stream.JumpToBit(ModuleBit);
auto *R = auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification,
new BitcodeReader(std::move(Stream), ProducerIdentification, Context); Context);
std::unique_ptr<Module> M = std::unique_ptr<Module> M =
llvm::make_unique<Module>(ModuleIdentifier, Context); llvm::make_unique<Module>(ModuleIdentifier, Context);
@ -5332,7 +5491,7 @@ Expected<std::unique_ptr<ModuleSummaryIndex>> BitcodeModule::getSummary() {
Stream.JumpToBit(ModuleBit); Stream.JumpToBit(ModuleBit);
auto Index = llvm::make_unique<ModuleSummaryIndex>(); auto Index = llvm::make_unique<ModuleSummaryIndex>();
ModuleSummaryIndexBitcodeReader R(std::move(Stream), *Index); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index);
if (Error Err = R.parseModule(ModuleIdentifier)) if (Error Err = R.parseModule(ModuleIdentifier))
return std::move(Err); return std::move(Err);

View File

@ -28,6 +28,7 @@
#include "llvm/IR/Operator.h" #include "llvm/IR/Operator.h"
#include "llvm/IR/UseListOrder.h" #include "llvm/IR/UseListOrder.h"
#include "llvm/IR/ValueSymbolTable.h" #include "llvm/IR/ValueSymbolTable.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h" #include "llvm/Support/MathExtras.h"
#include "llvm/Support/Program.h" #include "llvm/Support/Program.h"
@ -76,26 +77,28 @@ protected:
/// The stream created and owned by the client. /// The stream created and owned by the client.
BitstreamWriter &Stream; BitstreamWriter &Stream;
/// Saves the offset of the VSTOffset record that must eventually be
/// backpatched with the offset of the actual VST.
uint64_t VSTOffsetPlaceholder = 0;
public: public:
/// Constructs a BitcodeWriterBase object that writes to the provided /// Constructs a BitcodeWriterBase object that writes to the provided
/// \p Stream. /// \p Stream.
BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {} BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {}
protected: protected:
bool hasVSTOffsetPlaceholder() { return VSTOffsetPlaceholder != 0; }
void writeValueSymbolTableForwardDecl();
void writeBitcodeHeader(); void writeBitcodeHeader();
void writeModuleVersion();
}; };
void BitcodeWriterBase::writeModuleVersion() {
// VERSION: [version#]
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, ArrayRef<uint64_t>{2});
}
/// Class to manage the bitcode writing for a module. /// Class to manage the bitcode writing for a module.
class ModuleBitcodeWriter : public BitcodeWriterBase { class ModuleBitcodeWriter : public BitcodeWriterBase {
/// Pointer to the buffer allocated by caller for bitcode writing. /// Pointer to the buffer allocated by caller for bitcode writing.
const SmallVectorImpl<char> &Buffer; const SmallVectorImpl<char> &Buffer;
StringTableBuilder &StrtabBuilder;
/// The Module to write to bitcode. /// The Module to write to bitcode.
const Module &M; const Module &M;
@ -127,15 +130,20 @@ class ModuleBitcodeWriter : public BitcodeWriterBase {
/// Tracks the last value id recorded in the GUIDToValueMap. /// Tracks the last value id recorded in the GUIDToValueMap.
unsigned GlobalValueId; unsigned GlobalValueId;
/// Saves the offset of the VSTOffset record that must eventually be
/// backpatched with the offset of the actual VST.
uint64_t VSTOffsetPlaceholder = 0;
public: public:
/// Constructs a ModuleBitcodeWriter object for the given Module, /// Constructs a ModuleBitcodeWriter object for the given Module,
/// writing to the provided \p Buffer. /// writing to the provided \p Buffer.
ModuleBitcodeWriter(const Module *M, SmallVectorImpl<char> &Buffer, ModuleBitcodeWriter(const Module *M, SmallVectorImpl<char> &Buffer,
StringTableBuilder &StrtabBuilder,
BitstreamWriter &Stream, bool ShouldPreserveUseListOrder, BitstreamWriter &Stream, bool ShouldPreserveUseListOrder,
const ModuleSummaryIndex *Index, bool GenerateHash, const ModuleSummaryIndex *Index, bool GenerateHash,
ModuleHash *ModHash = nullptr) ModuleHash *ModHash = nullptr)
: BitcodeWriterBase(Stream), Buffer(Buffer), M(*M), : BitcodeWriterBase(Stream), Buffer(Buffer), StrtabBuilder(StrtabBuilder),
VE(*M, ShouldPreserveUseListOrder), Index(Index), M(*M), VE(*M, ShouldPreserveUseListOrder), Index(Index),
GenerateHash(GenerateHash), ModHash(ModHash), GenerateHash(GenerateHash), ModHash(ModHash),
BitcodeStartBit(Stream.GetCurrentBitNo()) { BitcodeStartBit(Stream.GetCurrentBitNo()) {
// Assign ValueIds to any callee values in the index that came from // Assign ValueIds to any callee values in the index that came from
@ -169,6 +177,7 @@ private:
void writeAttributeTable(); void writeAttributeTable();
void writeTypeTable(); void writeTypeTable();
void writeComdats(); void writeComdats();
void writeValueSymbolTableForwardDecl();
void writeModuleInfo(); void writeModuleInfo();
void writeValueAsMetadata(const ValueAsMetadata *MD, void writeValueAsMetadata(const ValueAsMetadata *MD,
SmallVectorImpl<uint64_t> &Record); SmallVectorImpl<uint64_t> &Record);
@ -261,9 +270,9 @@ private:
SmallVectorImpl<uint64_t> &Vals); SmallVectorImpl<uint64_t> &Vals);
void writeInstruction(const Instruction &I, unsigned InstID, void writeInstruction(const Instruction &I, unsigned InstID,
SmallVectorImpl<unsigned> &Vals); SmallVectorImpl<unsigned> &Vals);
void writeValueSymbolTable( void writeFunctionLevelValueSymbolTable(const ValueSymbolTable &VST);
const ValueSymbolTable &VST, bool IsModuleLevel = false, void writeGlobalValueSymbolTable(
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex = nullptr); DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex);
void writeUseList(UseListOrder &&Order); void writeUseList(UseListOrder &&Order);
void writeUseListBlock(const Function *F); void writeUseListBlock(const Function *F);
void void
@ -477,7 +486,6 @@ public:
private: private:
void writeModStrings(); void writeModStrings();
void writeCombinedValueSymbolTable();
void writeCombinedGlobalValueSummary(); void writeCombinedGlobalValueSummary();
/// Indicates whether the provided \p ModulePath should be written into /// Indicates whether the provided \p ModulePath should be written into
@ -492,15 +500,15 @@ private:
const auto &VMI = GUIDToValueIdMap.find(ValGUID); const auto &VMI = GUIDToValueIdMap.find(ValGUID);
return VMI != GUIDToValueIdMap.end(); return VMI != GUIDToValueIdMap.end();
} }
void assignValueId(GlobalValue::GUID ValGUID) {
unsigned &ValueId = GUIDToValueIdMap[ValGUID];
if (ValueId == 0)
ValueId = ++GlobalValueId;
}
unsigned getValueId(GlobalValue::GUID ValGUID) { unsigned getValueId(GlobalValue::GUID ValGUID) {
const auto &VMI = GUIDToValueIdMap.find(ValGUID); auto VMI = GUIDToValueIdMap.find(ValGUID);
// If this GUID doesn't have an entry, assign one. assert(VMI != GUIDToValueIdMap.end());
if (VMI == GUIDToValueIdMap.end()) { return VMI->second;
GUIDToValueIdMap[ValGUID] = ++GlobalValueId;
return GlobalValueId;
} else {
return VMI->second;
}
} }
std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; } std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; }
}; };
@ -1047,13 +1055,10 @@ static unsigned getEncodedUnnamedAddr(const GlobalValue &GV) {
void ModuleBitcodeWriter::writeComdats() { void ModuleBitcodeWriter::writeComdats() {
SmallVector<unsigned, 64> Vals; SmallVector<unsigned, 64> Vals;
for (const Comdat *C : VE.getComdats()) { for (const Comdat *C : VE.getComdats()) {
// COMDAT: [selection_kind, name] // COMDAT: [strtab offset, strtab size, selection_kind]
Vals.push_back(StrtabBuilder.add(C->getName()));
Vals.push_back(C->getName().size());
Vals.push_back(getEncodedComdatSelectionKind(*C)); Vals.push_back(getEncodedComdatSelectionKind(*C));
size_t Size = C->getName().size();
assert(isUInt<32>(Size));
Vals.push_back(Size);
for (char Chr : C->getName())
Vals.push_back((unsigned char)Chr);
Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0); Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0);
Vals.clear(); Vals.clear();
} }
@ -1062,7 +1067,7 @@ void ModuleBitcodeWriter::writeComdats() {
/// Write a record that will eventually hold the word offset of the /// Write a record that will eventually hold the word offset of the
/// module-level VST. For now the offset is 0, which will be backpatched /// module-level VST. For now the offset is 0, which will be backpatched
/// after the real VST is written. Saves the bit offset to backpatch. /// after the real VST is written. Saves the bit offset to backpatch.
void BitcodeWriterBase::writeValueSymbolTableForwardDecl() { void ModuleBitcodeWriter::writeValueSymbolTableForwardDecl() {
// Write a placeholder value in for the offset of the real VST, // Write a placeholder value in for the offset of the real VST,
// which is written after the function blocks so that it can include // which is written after the function blocks so that it can include
// the offset of each function. The placeholder offset will be // the offset of each function. The placeholder offset will be
@ -1165,6 +1170,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// Add an abbrev for common globals with no visibility or thread localness. // Add an abbrev for common globals with no visibility or thread localness.
auto Abbv = std::make_shared<BitCodeAbbrev>(); auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR)); Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
Log2_32_Ceil(MaxGlobalType+1))); Log2_32_Ceil(MaxGlobalType+1)));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2
@ -1188,15 +1195,42 @@ void ModuleBitcodeWriter::writeModuleInfo() {
SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv)); SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv));
} }
// Emit the global variable information.
SmallVector<unsigned, 64> Vals; SmallVector<unsigned, 64> Vals;
// Emit the module's source file name.
{
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
M.getSourceFileName().size());
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
if (Bits == SE_Char6)
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
else if (Bits == SE_Fixed7)
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7);
// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_SOURCE_FILENAME));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(AbbrevOpToUse);
unsigned FilenameAbbrev = Stream.EmitAbbrev(std::move(Abbv));
for (const auto P : M.getSourceFileName())
Vals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(bitc::MODULE_CODE_SOURCE_FILENAME, Vals, FilenameAbbrev);
Vals.clear();
}
// Emit the global variable information.
for (const GlobalVariable &GV : M.globals()) { for (const GlobalVariable &GV : M.globals()) {
unsigned AbbrevToUse = 0; unsigned AbbrevToUse = 0;
// GLOBALVAR: [type, isconst, initid, // GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal, // linkage, alignment, section, visibility, threadlocal,
// unnamed_addr, externally_initialized, dllstorageclass, // unnamed_addr, externally_initialized, dllstorageclass,
// comdat] // comdat]
Vals.push_back(StrtabBuilder.add(GV.getName()));
Vals.push_back(GV.getName().size());
Vals.push_back(VE.getTypeID(GV.getValueType())); Vals.push_back(VE.getTypeID(GV.getValueType()));
Vals.push_back(GV.getType()->getAddressSpace() << 2 | 2 | GV.isConstant()); Vals.push_back(GV.getType()->getAddressSpace() << 2 | 2 | GV.isConstant());
Vals.push_back(GV.isDeclaration() ? 0 : Vals.push_back(GV.isDeclaration() ? 0 :
@ -1226,9 +1260,12 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// Emit the function proto information. // Emit the function proto information.
for (const Function &F : M) { for (const Function &F : M) {
// FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, // FUNCTION: [strtab offset, strtab size, type, callingconv, isproto,
// section, visibility, gc, unnamed_addr, prologuedata, // linkage, paramattrs, alignment, section, visibility, gc,
// dllstorageclass, comdat, prefixdata, personalityfn] // unnamed_addr, prologuedata, dllstorageclass, comdat,
// prefixdata, personalityfn]
Vals.push_back(StrtabBuilder.add(F.getName()));
Vals.push_back(F.getName().size());
Vals.push_back(VE.getTypeID(F.getFunctionType())); Vals.push_back(VE.getTypeID(F.getFunctionType()));
Vals.push_back(F.getCallingConv()); Vals.push_back(F.getCallingConv());
Vals.push_back(F.isDeclaration()); Vals.push_back(F.isDeclaration());
@ -1255,8 +1292,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// Emit the alias information. // Emit the alias information.
for (const GlobalAlias &A : M.aliases()) { for (const GlobalAlias &A : M.aliases()) {
// ALIAS: [alias type, aliasee val#, linkage, visibility, dllstorageclass, // ALIAS: [strtab offset, strtab size, alias type, aliasee val#, linkage,
// threadlocal, unnamed_addr] // visibility, dllstorageclass, threadlocal, unnamed_addr]
Vals.push_back(StrtabBuilder.add(A.getName()));
Vals.push_back(A.getName().size());
Vals.push_back(VE.getTypeID(A.getValueType())); Vals.push_back(VE.getTypeID(A.getValueType()));
Vals.push_back(A.getType()->getAddressSpace()); Vals.push_back(A.getType()->getAddressSpace());
Vals.push_back(VE.getValueID(A.getAliasee())); Vals.push_back(VE.getValueID(A.getAliasee()));
@ -1272,7 +1311,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// Emit the ifunc information. // Emit the ifunc information.
for (const GlobalIFunc &I : M.ifuncs()) { for (const GlobalIFunc &I : M.ifuncs()) {
// IFUNC: [ifunc type, address space, resolver val#, linkage, visibility] // IFUNC: [strtab offset, strtab size, ifunc type, address space, resolver
// val#, linkage, visibility]
Vals.push_back(StrtabBuilder.add(I.getName()));
Vals.push_back(I.getName().size());
Vals.push_back(VE.getTypeID(I.getValueType())); Vals.push_back(VE.getTypeID(I.getValueType()));
Vals.push_back(I.getType()->getAddressSpace()); Vals.push_back(I.getType()->getAddressSpace());
Vals.push_back(VE.getValueID(I.getResolver())); Vals.push_back(VE.getValueID(I.getResolver()));
@ -1282,34 +1324,6 @@ void ModuleBitcodeWriter::writeModuleInfo() {
Vals.clear(); Vals.clear();
} }
// Emit the module's source file name.
{
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
M.getSourceFileName().size());
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
if (Bits == SE_Char6)
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
else if (Bits == SE_Fixed7)
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7);
// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_SOURCE_FILENAME));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(AbbrevOpToUse);
unsigned FilenameAbbrev = Stream.EmitAbbrev(std::move(Abbv));
for (const auto P : M.getSourceFileName())
Vals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(bitc::MODULE_CODE_SOURCE_FILENAME, Vals, FilenameAbbrev);
Vals.clear();
}
// If we have a VST, write the VSTOFFSET record placeholder.
if (M.getValueSymbolTable().empty())
return;
writeValueSymbolTableForwardDecl(); writeValueSymbolTableForwardDecl();
} }
@ -2839,78 +2853,60 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
Vals.clear(); Vals.clear();
} }
/// Emit names for globals/functions etc. \p IsModuleLevel is true when /// Write a GlobalValue VST to the module. The purpose of this data structure is
/// we are writing the module-level VST, where we are including a function /// to allow clients to efficiently find the function body.
/// bitcode index and need to backpatch the VST forward declaration record. void ModuleBitcodeWriter::writeGlobalValueSymbolTable(
void ModuleBitcodeWriter::writeValueSymbolTable( DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex) {
const ValueSymbolTable &VST, bool IsModuleLevel, // Get the offset of the VST we are writing, and backpatch it into
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex) { // the VST forward declaration record.
if (VST.empty()) { uint64_t VSTOffset = Stream.GetCurrentBitNo();
// writeValueSymbolTableForwardDecl should have returned early as // The BitcodeStartBit was the stream offset of the identification block.
// well. Ensure this handling remains in sync by asserting that VSTOffset -= bitcodeStartBit();
// the placeholder offset is not set. assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
assert(!IsModuleLevel || !hasVSTOffsetPlaceholder()); // Note that we add 1 here because the offset is relative to one word
return; // before the start of the identification block, which was historically
} // always the start of the regular bitcode header.
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32 + 1);
if (IsModuleLevel && hasVSTOffsetPlaceholder()) {
// Get the offset of the VST we are writing, and backpatch it into
// the VST forward declaration record.
uint64_t VSTOffset = Stream.GetCurrentBitNo();
// The BitcodeStartBit was the stream offset of the identification block.
VSTOffset -= bitcodeStartBit();
assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
// Note that we add 1 here because the offset is relative to one word
// before the start of the identification block, which was historically
// always the start of the regular bitcode header.
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32 + 1);
}
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4); Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
// For the module-level VST, add abbrev Ids for the VST_CODE_FNENTRY auto Abbv = std::make_shared<BitCodeAbbrev>();
// records, which are not used in the per-function VSTs. Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
unsigned FnEntry8BitAbbrev; Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
unsigned FnEntry7BitAbbrev; Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
unsigned FnEntry6BitAbbrev; unsigned FnEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
unsigned GUIDEntryAbbrev;
if (IsModuleLevel && hasVSTOffsetPlaceholder()) {
// 8-bit fixed-width VST_CODE_FNENTRY function strings.
auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
FnEntry8BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
// 7-bit fixed width VST_CODE_FNENTRY function strings. for (const Function &F : M) {
Abbv = std::make_shared<BitCodeAbbrev>(); uint64_t Record[2];
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7));
FnEntry7BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
// 6-bit char6 VST_CODE_FNENTRY function strings. if (F.isDeclaration())
Abbv = std::make_shared<BitCodeAbbrev>(); continue;
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6));
FnEntry6BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
// FIXME: Change the name of this record as it is now used by Record[0] = VE.getValueID(&F);
// the per-module index as well.
Abbv = std::make_shared<BitCodeAbbrev>(); // Save the word offset of the function (from the start of the
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_ENTRY)); // actual bitcode written to the stream).
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid uint64_t BitcodeIndex = FunctionToBitcodeIndex[&F] - bitcodeStartBit();
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // refguid assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
GUIDEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv)); // Note that we add 1 here because the offset is relative to one word
// before the start of the identification block, which was historically
// always the start of the regular bitcode header.
Record[1] = BitcodeIndex / 32 + 1;
Stream.EmitRecord(bitc::VST_CODE_FNENTRY, Record, FnEntryAbbrev);
} }
Stream.ExitBlock();
}
/// Emit names for arguments, instructions and basic blocks in a function.
void ModuleBitcodeWriter::writeFunctionLevelValueSymbolTable(
const ValueSymbolTable &VST) {
if (VST.empty())
return;
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
// FIXME: Set up the abbrev, we know how many values there are! // FIXME: Set up the abbrev, we know how many values there are!
// FIXME: We know if the type names can use 7-bit ascii. // FIXME: We know if the type names can use 7-bit ascii.
SmallVector<uint64_t, 64> NameVals; SmallVector<uint64_t, 64> NameVals;
@ -2923,38 +2919,13 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
unsigned AbbrevToUse = VST_ENTRY_8_ABBREV; unsigned AbbrevToUse = VST_ENTRY_8_ABBREV;
NameVals.push_back(VE.getValueID(Name.getValue())); NameVals.push_back(VE.getValueID(Name.getValue()));
Function *F = dyn_cast<Function>(Name.getValue());
// VST_CODE_ENTRY: [valueid, namechar x N] // VST_CODE_ENTRY: [valueid, namechar x N]
// VST_CODE_FNENTRY: [valueid, funcoffset, namechar x N]
// VST_CODE_BBENTRY: [bbid, namechar x N] // VST_CODE_BBENTRY: [bbid, namechar x N]
unsigned Code; unsigned Code;
if (isa<BasicBlock>(Name.getValue())) { if (isa<BasicBlock>(Name.getValue())) {
Code = bitc::VST_CODE_BBENTRY; Code = bitc::VST_CODE_BBENTRY;
if (Bits == SE_Char6) if (Bits == SE_Char6)
AbbrevToUse = VST_BBENTRY_6_ABBREV; AbbrevToUse = VST_BBENTRY_6_ABBREV;
} else if (F && !F->isDeclaration()) {
// Must be the module-level VST, where we pass in the Index and
// have a VSTOffsetPlaceholder. The function-level VST should not
// contain any Function symbols.
assert(FunctionToBitcodeIndex);
assert(hasVSTOffsetPlaceholder());
// Save the word offset of the function (from the start of the
// actual bitcode written to the stream).
uint64_t BitcodeIndex = (*FunctionToBitcodeIndex)[F] - bitcodeStartBit();
assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
// Note that we add 1 here because the offset is relative to one word
// before the start of the identification block, which was historically
// always the start of the regular bitcode header.
NameVals.push_back(BitcodeIndex / 32 + 1);
Code = bitc::VST_CODE_FNENTRY;
AbbrevToUse = FnEntry8BitAbbrev;
if (Bits == SE_Char6)
AbbrevToUse = FnEntry6BitAbbrev;
else if (Bits == SE_Fixed7)
AbbrevToUse = FnEntry7BitAbbrev;
} else { } else {
Code = bitc::VST_CODE_ENTRY; Code = bitc::VST_CODE_ENTRY;
if (Bits == SE_Char6) if (Bits == SE_Char6)
@ -2970,47 +2941,7 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
Stream.EmitRecord(Code, NameVals, AbbrevToUse); Stream.EmitRecord(Code, NameVals, AbbrevToUse);
NameVals.clear(); NameVals.clear();
} }
// Emit any GUID valueIDs created for indirect call edges into the
// module-level VST.
if (IsModuleLevel && hasVSTOffsetPlaceholder())
for (const auto &GI : valueIds()) {
NameVals.push_back(GI.second);
NameVals.push_back(GI.first);
Stream.EmitRecord(bitc::VST_CODE_COMBINED_ENTRY, NameVals,
GUIDEntryAbbrev);
NameVals.clear();
}
Stream.ExitBlock();
}
/// Emit function names and summary offsets for the combined index
/// used by ThinLTO.
void IndexBitcodeWriter::writeCombinedValueSymbolTable() {
assert(hasVSTOffsetPlaceholder() && "Expected non-zero VSTOffsetPlaceholder");
// Get the offset of the VST we are writing, and backpatch it into
// the VST forward declaration record.
uint64_t VSTOffset = Stream.GetCurrentBitNo();
assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32);
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // refguid
unsigned EntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
SmallVector<uint64_t, 64> NameVals;
for (const auto &GVI : valueIds()) {
// VST_CODE_COMBINED_ENTRY: [valueid, refguid]
NameVals.push_back(GVI.second);
NameVals.push_back(GVI.first);
// Emit the finished record.
Stream.EmitRecord(bitc::VST_CODE_COMBINED_ENTRY, NameVals, EntryAbbrev);
NameVals.clear();
}
Stream.ExitBlock(); Stream.ExitBlock();
} }
@ -3114,7 +3045,7 @@ void ModuleBitcodeWriter::writeFunction(
// Emit names for all the instructions etc. // Emit names for all the instructions etc.
if (auto *Symtab = F.getValueSymbolTable()) if (auto *Symtab = F.getValueSymbolTable())
writeValueSymbolTable(*Symtab); writeFunctionLevelValueSymbolTable(*Symtab);
if (NeedsMetadataAttachment) if (NeedsMetadataAttachment)
writeFunctionMetadataAttachment(F); writeFunctionMetadataAttachment(F);
@ -3502,6 +3433,11 @@ void ModuleBitcodeWriter::writePerModuleGlobalValueSummary() {
return; return;
} }
for (const auto &GVI : valueIds()) {
Stream.EmitRecord(bitc::FS_VALUE_GUID,
ArrayRef<uint64_t>{GVI.second, GVI.first});
}
// Abbrev for FS_PERMODULE. // Abbrev for FS_PERMODULE.
auto Abbv = std::make_shared<BitCodeAbbrev>(); auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE)); Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE));
@ -3594,6 +3530,39 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3); Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3);
Stream.EmitRecord(bitc::FS_VERSION, ArrayRef<uint64_t>{INDEX_VERSION}); Stream.EmitRecord(bitc::FS_VERSION, ArrayRef<uint64_t>{INDEX_VERSION});
// Create value IDs for undefined references.
for (const auto &I : *this) {
if (auto *VS = dyn_cast<GlobalVarSummary>(I.second)) {
for (auto &RI : VS->refs())
assignValueId(RI.getGUID());
continue;
}
auto *FS = dyn_cast<FunctionSummary>(I.second);
if (!FS)
continue;
for (auto &RI : FS->refs())
assignValueId(RI.getGUID());
for (auto &EI : FS->calls()) {
GlobalValue::GUID GUID = EI.first.getGUID();
if (!hasValueId(GUID)) {
// For SamplePGO, the indirect call targets for local functions will
// have its original name annotated in profile. We try to find the
// corresponding PGOFuncName as the GUID.
GUID = Index.getGUIDFromOriginalID(GUID);
if (GUID == 0 || !hasValueId(GUID))
continue;
}
assignValueId(GUID);
}
}
for (const auto &GVI : valueIds()) {
Stream.EmitRecord(bitc::FS_VALUE_GUID,
ArrayRef<uint64_t>{GVI.second, GVI.first});
}
// Abbrev for FS_COMBINED. // Abbrev for FS_COMBINED.
auto Abbv = std::make_shared<BitCodeAbbrev>(); auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::FS_COMBINED)); Abbv->Add(BitCodeAbbrevOp(bitc::FS_COMBINED));
@ -3808,10 +3777,7 @@ void ModuleBitcodeWriter::write() {
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
size_t BlockStartPos = Buffer.size(); size_t BlockStartPos = Buffer.size();
SmallVector<unsigned, 1> Vals; writeModuleVersion();
unsigned CurVersion = 1;
Vals.push_back(CurVersion);
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals);
// Emit blockinfo, which defines the standard abbreviations etc. // Emit blockinfo, which defines the standard abbreviations etc.
writeBlockInfo(); writeBlockInfo();
@ -3857,8 +3823,7 @@ void ModuleBitcodeWriter::write() {
if (Index) if (Index)
writePerModuleGlobalValueSummary(); writePerModuleGlobalValueSummary();
writeValueSymbolTable(M.getValueSymbolTable(), writeGlobalValueSymbolTable(FunctionToBitcodeIndex);
/* IsModuleLevel */ true, &FunctionToBitcodeIndex);
writeModuleHash(BlockStartPos); writeModuleHash(BlockStartPos);
@ -3946,13 +3911,45 @@ BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer)
writeBitcodeHeader(*Stream); writeBitcodeHeader(*Stream);
} }
BitcodeWriter::~BitcodeWriter() = default; BitcodeWriter::~BitcodeWriter() { assert(WroteStrtab); }
void BitcodeWriter::writeBlob(unsigned Block, unsigned Record, StringRef Blob) {
Stream->EnterSubblock(Block, 3);
auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(Record));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
auto AbbrevNo = Stream->EmitAbbrev(std::move(Abbv));
Stream->EmitRecordWithBlob(AbbrevNo, ArrayRef<uint64_t>{Record}, Blob);
Stream->ExitBlock();
}
void BitcodeWriter::writeStrtab() {
assert(!WroteStrtab);
std::vector<char> Strtab;
StrtabBuilder.finalizeInOrder();
Strtab.resize(StrtabBuilder.getSize());
StrtabBuilder.write((uint8_t *)Strtab.data());
writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB,
{Strtab.data(), Strtab.size()});
WroteStrtab = true;
}
void BitcodeWriter::copyStrtab(StringRef Strtab) {
writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB, Strtab);
WroteStrtab = true;
}
void BitcodeWriter::writeModule(const Module *M, void BitcodeWriter::writeModule(const Module *M,
bool ShouldPreserveUseListOrder, bool ShouldPreserveUseListOrder,
const ModuleSummaryIndex *Index, const ModuleSummaryIndex *Index,
bool GenerateHash, ModuleHash *ModHash) { bool GenerateHash, ModuleHash *ModHash) {
ModuleBitcodeWriter ModuleWriter(M, Buffer, *Stream, ModuleBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream,
ShouldPreserveUseListOrder, Index, ShouldPreserveUseListOrder, Index,
GenerateHash, ModHash); GenerateHash, ModHash);
ModuleWriter.write(); ModuleWriter.write();
@ -3976,6 +3973,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
BitcodeWriter Writer(Buffer); BitcodeWriter Writer(Buffer);
Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash, Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash,
ModHash); ModHash);
Writer.writeStrtab();
if (TT.isOSDarwin() || TT.isOSBinFormatMachO()) if (TT.isOSDarwin() || TT.isOSBinFormatMachO())
emitDarwinBCHeaderAndTrailer(Buffer, TT); emitDarwinBCHeaderAndTrailer(Buffer, TT);
@ -3987,13 +3985,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
void IndexBitcodeWriter::write() { void IndexBitcodeWriter::write() {
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
SmallVector<unsigned, 1> Vals; writeModuleVersion();
unsigned CurVersion = 1;
Vals.push_back(CurVersion);
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals);
// If we have a VST, write the VSTOFFSET record placeholder.
writeValueSymbolTableForwardDecl();
// Write the module paths in the combined index. // Write the module paths in the combined index.
writeModStrings(); writeModStrings();
@ -4001,10 +3993,6 @@ void IndexBitcodeWriter::write() {
// Write the summary combined index records. // Write the summary combined index records.
writeCombinedGlobalValueSummary(); writeCombinedGlobalValueSummary();
// Need a special VST writer for the combined index (we don't have a
// real VST and real values when this is invoked).
writeCombinedValueSymbolTable();
Stream.ExitBlock(); Stream.ExitBlock();
} }

View File

@ -363,6 +363,7 @@ void splitAndWriteThinLTOBitcode(
W.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index, W.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index,
/*GenerateHash=*/true, &ModHash); /*GenerateHash=*/true, &ModHash);
W.writeModule(MergedM.get()); W.writeModule(MergedM.get());
W.writeStrtab();
OS << Buffer; OS << Buffer;
// If a minimized bitcode module was requested for the thin link, // If a minimized bitcode module was requested for the thin link,
@ -375,6 +376,7 @@ void splitAndWriteThinLTOBitcode(
W2.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index, W2.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index,
/*GenerateHash=*/false, &ModHash); /*GenerateHash=*/false, &ModHash);
W2.writeModule(MergedM.get()); W2.writeModule(MergedM.get());
W2.writeStrtab();
*ThinLinkOS << Buffer; *ThinLinkOS << Buffer;
} }
} }

View File

@ -5,33 +5,31 @@
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o ; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED ; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
; CHECK: <SOURCE_FILENAME
; "main"
; CHECK-NEXT: <FUNCTION op0=0 op1=4
; "analias"
; CHECK-NEXT: <FUNCTION op0=4 op1=7
; CHECK: <GLOBALVAL_SUMMARY_BLOCK ; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION ; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count ; See if the call to func is registered.
; and value id matching the subsequent value symbol table. ; The value id 1 matches the second FUNCTION record above.
; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/> ; CHECK-NEXT: <PERMODULE {{.*}} op4=1/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main' ; CHECK: <STRTAB_BLOCK
; External function analias should have entry with value id FUNCID ; CHECK-NEXT: blob data = 'mainanalias'
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'analias'
; CHECK-NEXT: </VALUE_SYMTAB>
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; See if the call to analias is registered, using the expected callsite count ; See if the call to analias is registered, using the expected value id.
; and value id matching the subsequent value symbol table. ; COMBINED-NEXT: <VALUE_GUID op0=[[ALIASID:[0-9]+]] op1=-5751648690987223394/>
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID:[0-9]+]]/> ; COMBINED-NEXT: <VALUE_GUID
; Followed by the alias and aliasee ; COMBINED-NEXT: <VALUE_GUID op0=[[ALIASEEID:[0-9]+]] op1=-1039159065113703048/>
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID]]/>
; COMBINED-NEXT: <COMBINED {{.*}} ; COMBINED-NEXT: <COMBINED {{.*}}
; COMBINED-NEXT: <COMBINED_ALIAS {{.*}} op3=[[ALIASEEID:[0-9]+]] ; COMBINED-NEXT: <COMBINED_ALIAS {{.*}} op3=[[ALIASEEID]]
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VALUE_SYMTAB
; Entry for function func should have entry with value id ALIASID
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op0=[[ALIASID]] op1=-5751648690987223394/>
; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op0=[[ALIASEEID]] op1=-1039159065113703048/>
; COMBINED-NEXT: </VALUE_SYMTAB>
; ModuleID = 'thinlto-function-summary-callgraph.ll' ; ModuleID = 'thinlto-function-summary-callgraph.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -10,31 +10,27 @@
; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo.1.bc | FileCheck %s --check-prefix=OLD ; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo.1.bc | FileCheck %s --check-prefix=OLD
; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED ; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED
; CHECK: <SOURCE_FILENAME
; CHECK-NEXT: <FUNCTION
; "func"
; CHECK-NEXT: <FUNCTION op0=4 op1=4
; CHECK: <GLOBALVAL_SUMMARY_BLOCK ; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION ; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count ; See if the call to func is registered, using the expected hotness type.
; and hotness type, with value id matching the subsequent value symbol table. ; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=1 op5=2/>
; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[FUNCID:[0-9]+]] op5=2/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB ; CHECK: <STRTAB_BLOCK
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main' ; CHECK-NEXT: blob data = 'mainfunc'
; External function func should have entry with value id FUNCID
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'func'
; CHECK-NEXT: </VALUE_SYMTAB>
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID op0=[[FUNCID:[0-9]+]] op1=7289175272376759421/>
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; See if the call to func is registered, using the expected callsite count ; See if the call to func is registered, using the expected hotness type.
; and hotness type, with value id matching the subsequent value symbol table.
; op6=2 which is hotnessType::None. ; op6=2 which is hotnessType::None.
; COMBINED-NEXT: <COMBINED_PROFILE {{.*}} op5=[[FUNCID:[0-9]+]] op6=2/> ; COMBINED-NEXT: <COMBINED_PROFILE {{.*}} op5=[[FUNCID]] op6=2/>
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; COMBINED-NEXT: <VALUE_SYMTAB
; Entry for function func should have entry with value id FUNCID
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op0=[[FUNCID]] op1=7289175272376759421/>
; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: </VALUE_SYMTAB>
; ModuleID = 'thinlto-function-summary-callgraph.ll' ; ModuleID = 'thinlto-function-summary-callgraph.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -6,27 +6,45 @@
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED ; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
; CHECK: <SOURCE_FILENAME
; "hot_function"
; CHECK-NEXT: <FUNCTION op0=0 op1=12
; "hot1"
; CHECK-NEXT: <FUNCTION op0=12 op1=4
; "hot2"
; CHECK-NEXT: <FUNCTION op0=16 op1=4
; "hot3"
; CHECK-NEXT: <FUNCTION op0=20 op1=4
; "hot4"
; CHECK-NEXT: <FUNCTION op0=24 op1=4
; "cold"
; CHECK-NEXT: <FUNCTION op0=28 op1=4
; "none1"
; CHECK-NEXT: <FUNCTION op0=32 op1=5
; "none2"
; CHECK-NEXT: <FUNCTION op0=37 op1=5
; "none3"
; CHECK-NEXT: <FUNCTION op0=42 op1=5
; CHECK-LABEL: <GLOBALVAL_SUMMARY_BLOCK ; CHECK-LABEL: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION ; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count ; CHECK-NEXT: <VALUE_GUID op0=25 op1=123/>
; and profile count, with value id matching the subsequent value symbol table. ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123
; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[HOT1:.*]] op5=3 op6=[[COLD:.*]] op7=1 op8=[[HOT2:.*]] op9=3 op10=[[HOT4:.*]] op11=3 op12=[[NONE1:.*]] op13=2 op14=[[HOT3:.*]] op15=3 op16=[[NONE2:.*]] op17=2 op18=[[NONE3:.*]] op19=2 op20=[[LEGACY:.*]] op21=3/> ; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=1 op5=3 op6=5 op7=1 op8=2 op9=3 op10=4 op11=3 op12=6 op13=2 op14=3 op15=3 op16=7 op17=2 op18=8 op19=2 op20=25 op21=3/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-LABEL: <VALUE_SYMTAB
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'hot_function ; CHECK: <STRTAB_BLOCK
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE1]] {{.*}} record string = 'none1' ; CHECK-NEXT: blob data = 'hot_functionhot1hot2hot3hot4coldnone1none2none3'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[COLD]] {{.*}} record string = 'cold'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE2]] {{.*}} record string = 'none2'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE3]] {{.*}} record string = 'none3'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT1]] {{.*}} record string = 'hot1'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT2]] {{.*}} record string = 'hot2'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT3]] {{.*}} record string = 'hot3'
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT4]] {{.*}} record string = 'hot4'
; CHECK-DAG: <COMBINED_ENTRY abbrevid=11 op0=[[LEGACY]] op1=123/>
; CHECK-LABEL: </VALUE_SYMTAB>
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <COMBINED abbrevid= ; COMBINED-NEXT: <COMBINED abbrevid=
; COMBINED-NEXT: <COMBINED abbrevid= ; COMBINED-NEXT: <COMBINED abbrevid=
; COMBINED-NEXT: <COMBINED abbrevid= ; COMBINED-NEXT: <COMBINED abbrevid=

View File

@ -10,30 +10,27 @@
; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph.1.bc | FileCheck %s --check-prefix=OLD ; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph.1.bc | FileCheck %s --check-prefix=OLD
; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED ; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED
; CHECK: <SOURCE_FILENAME
; CHECK-NEXT: <FUNCTION
; "func"
; CHECK-NEXT: <FUNCTION op0=4 op1=4
; CHECK: <GLOBALVAL_SUMMARY_BLOCK ; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION ; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count ; See if the call to func is registered.
; and value id matching the subsequent value symbol table. ; CHECK-NEXT: <PERMODULE {{.*}} op4=1/>
; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB ; CHECK: <STRTAB_BLOCK
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main' ; CHECK-NEXT: blob data = 'mainfunc'
; External function func should have entry with value id FUNCID
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'func'
; CHECK-NEXT: </VALUE_SYMTAB>
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID op0=[[FUNCID:[0-9]+]] op1=7289175272376759421/>
; COMBINED-NEXT: <VALUE_GUID
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; See if the call to func is registered, using the expected callsite count ; See if the call to func is registered.
; and value id matching the subsequent value symbol table. ; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID]]/>
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID:[0-9]+]]/>
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; COMBINED-NEXT: <VALUE_SYMTAB
; Entry for function func should have entry with value id FUNCID
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op0=[[FUNCID]] op1=7289175272376759421/>
; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: </VALUE_SYMTAB>
; ModuleID = 'thinlto-function-summary-callgraph.ll' ; ModuleID = 'thinlto-function-summary-callgraph.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -5,6 +5,9 @@
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID {{.*}} op1=4947176790635855146/>
; COMBINED-NEXT: <VALUE_GUID {{.*}} op1=-6591587165810580810/>
; COMBINED-NEXT: <VALUE_GUID {{.*}} op1=-4377693495213223786/>
; COMBINED-DAG: <COMBINED ; COMBINED-DAG: <COMBINED
; COMBINED-DAG: <COMBINED_ORIGINAL_NAME op0=6699318081062747564/> ; COMBINED-DAG: <COMBINED_ORIGINAL_NAME op0=6699318081062747564/>
; COMBINED-DAG: <COMBINED_GLOBALVAR_INIT_REFS ; COMBINED-DAG: <COMBINED_GLOBALVAR_INIT_REFS
@ -12,11 +15,6 @@
; COMBINED-DAG: <COMBINED_ALIAS ; COMBINED-DAG: <COMBINED_ALIAS
; COMBINED-DAG: <COMBINED_ORIGINAL_NAME op0=-4170563161550796836/> ; COMBINED-DAG: <COMBINED_ORIGINAL_NAME op0=-4170563161550796836/>
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK> ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; COMBINED-NEXT: <VALUE_SYMTAB
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op1=4947176790635855146/>
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op1=-6591587165810580810/>
; COMBINED-NEXT: <COMBINED_ENTRY {{.*}} op1=-4377693495213223786/>
; COMBINED-NEXT: </VALUE_SYMTAB>
source_filename = "/path/to/source.c" source_filename = "/path/to/source.c"

View File

@ -2,6 +2,32 @@
; RUN: opt -module-summary %s -o %t.o ; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s ; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; CHECK: <SOURCE_FILENAME
; "bar"
; CHECK-NEXT: <GLOBALVAR {{.*}} op0=0 op1=3
; "globalvar"
; CHECK-NEXT: <GLOBALVAR {{.*}} op0=3 op1=9
; "func"
; CHECK-NEXT: <FUNCTION op0=12 op1=4
; "func2"
; CHECK-NEXT: <FUNCTION op0=16 op1=5
; "foo"
; CHECK-NEXT: <FUNCTION op0=21 op1=3
; "func3"
; CHECK-NEXT: <FUNCTION op0=24 op1=5
; "W"
; CHECK-NEXT: <FUNCTION op0=29 op1=1
; "X"
; CHECK-NEXT: <FUNCTION op0=30 op1=1
; "Y"
; CHECK-NEXT: <FUNCTION op0=31 op1=1
; "Z"
; CHECK-NEXT: <FUNCTION op0=32 op1=1
; "llvm.ctpop.i8"
; CHECK-NEXT: <FUNCTION op0=33 op1=13
; "main"
; CHECK-NEXT: <FUNCTION op0=46 op1=4
; See if the calls and other references are recorded properly using the ; See if the calls and other references are recorded properly using the
; expected value id and other information as appropriate (callsite cout ; expected value id and other information as appropriate (callsite cout
; for calls). Use different linkage types for the various test cases to ; for calls). Use different linkage types for the various test cases to
@ -11,37 +37,32 @@
; llvm.ctpop.i8. ; llvm.ctpop.i8.
; CHECK: <GLOBALVAL_SUMMARY_BLOCK ; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; Function main contains call to func, as well as address reference to func: ; Function main contains call to func, as well as address reference to func:
; CHECK-DAG: <PERMODULE {{.*}} op0=[[MAINID:[0-9]+]] op1=0 {{.*}} op3=1 op4=[[FUNCID:[0-9]+]] op5=[[FUNCID]]/> ; op0=main op4=func op5=func
; CHECK-DAG: <PERMODULE {{.*}} op0=11 op1=0 {{.*}} op3=1 op4=2 op5=2/>
; Function W contains a call to func3 as well as a reference to globalvar: ; Function W contains a call to func3 as well as a reference to globalvar:
; CHECK-DAG: <PERMODULE {{.*}} op0=[[WID:[0-9]+]] op1=5 {{.*}} op3=1 op4=[[GLOBALVARID:[0-9]+]] op5=[[FUNC3ID:[0-9]+]]/> ; op0=W op4=globalvar op5=func3
; CHECK-DAG: <PERMODULE {{.*}} op0=6 op1=5 {{.*}} op3=1 op4=1 op5=5/>
; Function X contains call to foo, as well as address reference to foo ; Function X contains call to foo, as well as address reference to foo
; which is in the same instruction as the call: ; which is in the same instruction as the call:
; CHECK-DAG: <PERMODULE {{.*}} op0=[[XID:[0-9]+]] op1=1 {{.*}} op3=1 op4=[[FOOID:[0-9]+]] op5=[[FOOID]]/> ; op0=X op4=foo op5=foo
; CHECK-DAG: <PERMODULE {{.*}} op0=7 op1=1 {{.*}} op3=1 op4=4 op5=4/>
; Function Y contains call to func2, and ensures we don't incorrectly add ; Function Y contains call to func2, and ensures we don't incorrectly add
; a reference to it when reached while earlier analyzing the phi using its ; a reference to it when reached while earlier analyzing the phi using its
; return value: ; return value:
; CHECK-DAG: <PERMODULE {{.*}} op0=[[YID:[0-9]+]] op1=8 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]]/> ; op0=Y op4=func2
; CHECK-DAG: <PERMODULE {{.*}} op0=8 op1=8 {{.*}} op3=0 op4=3/>
; Function Z contains call to func2, and ensures we don't incorrectly add ; Function Z contains call to func2, and ensures we don't incorrectly add
; a reference to it when reached while analyzing subsequent use of its return ; a reference to it when reached while analyzing subsequent use of its return
; value: ; value:
; CHECK-DAG: <PERMODULE {{.*}} op0=[[ZID:[0-9]+]] op1=3 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]]/> ; op0=Z op4=func2
; CHECK-DAG: <PERMODULE {{.*}} op0=9 op1=3 {{.*}} op3=0 op4=3/>
; Variable bar initialization contains address reference to func: ; Variable bar initialization contains address reference to func:
; CHECK-DAG: <PERMODULE_GLOBALVAR_INIT_REFS {{.*}} op0=[[BARID:[0-9]+]] op1=0 op2=[[FUNCID]]/> ; op0=bar op2=func
; CHECK-DAG: <PERMODULE_GLOBALVAR_INIT_REFS {{.*}} op0=0 op1=0 op2=2/>
; CHECK: </GLOBALVAL_SUMMARY_BLOCK> ; CHECK: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB ; CHECK: <STRTAB_BLOCK
; CHECK-DAG: <ENTRY {{.*}} op0=[[BARID]] {{.*}} record string = 'bar' ; CHECK-NEXT: blob data = 'barglobalvarfuncfunc2foofunc3WXYZllvm.ctpop.i8main'
; CHECK-DAG: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'func'
; CHECK-DAG: <ENTRY {{.*}} op0=[[FOOID]] {{.*}} record string = 'foo'
; CHECK-DAG: <FNENTRY {{.*}} op0=[[MAINID]] {{.*}} record string = 'main'
; CHECK-DAG: <FNENTRY {{.*}} op0=[[WID]] {{.*}} record string = 'W'
; CHECK-DAG: <FNENTRY {{.*}} op0=[[XID]] {{.*}} record string = 'X'
; CHECK-DAG: <FNENTRY {{.*}} op0=[[YID]] {{.*}} record string = 'Y'
; CHECK-DAG: <FNENTRY {{.*}} op0=[[ZID]] {{.*}} record string = 'Z'
; CHECK-DAG: <ENTRY {{.*}} op0=[[FUNC2ID]] {{.*}} record string = 'func2'
; CHECK-DAG: <ENTRY {{.*}} op0=[[FUNC3ID]] {{.*}} record string = 'func3'
; CHECK-DAG: <ENTRY {{.*}} op0=[[GLOBALVARID]] {{.*}} record string = 'globalvar'
; CHECK: </VALUE_SYMTAB>
; ModuleID = 'thinlto-function-summary-refgraph.ll' ; ModuleID = 'thinlto-function-summary-refgraph.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -2,9 +2,19 @@
; RUN: opt -passes=name-anon-globals -module-summary < %s | llvm-bcanalyzer -dump | FileCheck %s -check-prefix=BC ; RUN: opt -passes=name-anon-globals -module-summary < %s | llvm-bcanalyzer -dump | FileCheck %s -check-prefix=BC
; Check for summary block/records. ; Check for summary block/records.
; Check the value ids in the summary entries against the ; BC: <SOURCE_FILENAME
; same in the ValueSumbolTable, to ensure the ordering is stable. ; "h"
; Also check the linkage field on the summary entries. ; BC-NEXT: <GLOBALVAR {{.*}} op0=0 op1=1
; "foo"
; BC-NEXT: <FUNCTION op0=1 op1=3
; "bar"
; BC-NEXT: <FUNCTION op0=4 op1=3
; "anon.[32 chars].0"
; BC-NEXT: <FUNCTION op0=7 op1=39
; "variadic"
; BC-NEXT: <FUNCTION op0=46 op1=8
; "f"
; BC-NEXT: <ALIAS op0=54 op1=1
; BC: <GLOBALVAL_SUMMARY_BLOCK ; BC: <GLOBALVAL_SUMMARY_BLOCK
; BC-NEXT: <VERSION ; BC-NEXT: <VERSION
; BC-NEXT: <PERMODULE {{.*}} op0=1 op1=0 ; BC-NEXT: <PERMODULE {{.*}} op0=1 op1=0
@ -13,13 +23,8 @@
; BC-NEXT: <PERMODULE {{.*}} op0=4 op1=16 ; BC-NEXT: <PERMODULE {{.*}} op0=4 op1=16
; BC-NEXT: <ALIAS {{.*}} op0=5 op1=0 op2=3 ; BC-NEXT: <ALIAS {{.*}} op0=5 op1=0 op2=3
; BC-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; BC-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; BC-NEXT: <VALUE_SYMTAB ; BC: <STRTAB_BLOCK
; BC-NEXT: <FNENTRY {{.*}} op0=4 {{.*}}> record string = 'variadic' ; BC-NEXT: blob data = 'hfoobaranon.{{................................}}.0variadicf'
; BC-NEXT: <FNENTRY {{.*}} op0=1 {{.*}}> record string = 'foo'
; BC-NEXT: <FNENTRY {{.*}} op0=2 {{.*}}> record string = 'bar'
; BC-NEXT: <ENTRY {{.*}} op0=5 {{.*}}> record string = 'f'
; BC-NEXT: <ENTRY {{.*}} record string = 'h'
; BC-NEXT: <FNENTRY {{.*}} op0=3 {{.*}}> record string = 'anon.
; RUN: opt -name-anon-globals -module-summary < %s | llvm-dis | FileCheck %s ; RUN: opt -name-anon-globals -module-summary < %s | llvm-dis | FileCheck %s

View File

@ -9,10 +9,8 @@
; RUN: -import=globalfunc1:%p/Inputs/autoupgrade.bc %t.bc \ ; RUN: -import=globalfunc1:%p/Inputs/autoupgrade.bc %t.bc \
; RUN: | llvm-bcanalyzer -dump | FileCheck %s ; RUN: | llvm-bcanalyzer -dump | FileCheck %s
; CHECK: <STRTAB_BLOCK
; CHECK-NOT: 'llvm.invariant.start' ; CHECK-NEXT: blob data = 'mainglobalfunc1llvm.invariant.start.p0i8'
; CHECK: record string = 'llvm.invariant.start.p0i8'
; CHECK-NOT: 'llvm.invariant.start'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0" target triple = "x86_64-apple-macosx10.11.0"

View File

@ -13,15 +13,11 @@
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK ; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; BACKEND1-NEXT: <VERSION ; BACKEND1-NEXT: <VERSION
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <COMBINED ; BACKEND1-NEXT: <COMBINED
; BACKEND1-NEXT: <COMBINED ; BACKEND1-NEXT: <COMBINED
; BACKEND1-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; BACKEND1-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; BACKEND1-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; BACKEND1-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: </VALUE_SYMTAB
; The backend index for Input/distributed_indexes.ll contains summaries from ; The backend index for Input/distributed_indexes.ll contains summaries from
; itself only, as it does not import anything. ; itself only, as it does not import anything.
@ -30,13 +26,9 @@
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK ; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; BACKEND2-NEXT: <VERSION ; BACKEND2-NEXT: <VERSION
; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
; BACKEND2-NEXT: <COMBINED ; BACKEND2-NEXT: <COMBINED
; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; BACKEND2-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; BACKEND2-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0=1 op1=-5300342847281564238
; BACKEND2-NEXT: </VALUE_SYMTAB
declare void @g(...) declare void @g(...)

View File

@ -82,15 +82,11 @@
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK ; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; BACKEND1-NEXT: <VERSION ; BACKEND1-NEXT: <VERSION
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <COMBINED ; BACKEND1-NEXT: <COMBINED
; BACKEND1-NEXT: <COMBINED ; BACKEND1-NEXT: <COMBINED
; BACKEND1-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; BACKEND1-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; BACKEND1-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; BACKEND1-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; BACKEND1-NEXT: </VALUE_SYMTAB
; The backend index for Input/thinlto.ll contains summaries from itself only, ; The backend index for Input/thinlto.ll contains summaries from itself only,
; as it does not import anything. ; as it does not import anything.
@ -99,13 +95,9 @@
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK ; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; BACKEND2-NEXT: <VERSION ; BACKEND2-NEXT: <VERSION
; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
; BACKEND2-NEXT: <COMBINED ; BACKEND2-NEXT: <COMBINED
; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; BACKEND2-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; BACKEND2-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0=1 op1=-5300342847281564238
; BACKEND2-NEXT: </VALUE_SYMTAB
; COMBINED: <MODULE_STRTAB_BLOCK ; COMBINED: <MODULE_STRTAB_BLOCK
; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o' ; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
@ -113,15 +105,11 @@
; COMBINED-NEXT: </MODULE_STRTAB_BLOCK ; COMBINED-NEXT: </MODULE_STRTAB_BLOCK
; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; COMBINED-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: </VALUE_SYMTAB
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu" target triple = "x86_64-unknown-linux-gnu"

View File

@ -11,15 +11,11 @@
; COMBINED-NEXT: </MODULE_STRTAB_BLOCK ; COMBINED-NEXT: </MODULE_STRTAB_BLOCK
; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK ; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VERSION ; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: <COMBINED ; COMBINED-NEXT: <COMBINED
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK ; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK
; COMBINED-NEXT: <VALUE_SYMTAB
; Check that the format is: op0=valueid, op1=offset, op2=funcguid,
; where funcguid is the lower 64 bits of the function name MD5.
; COMBINED-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: <COMBINED_ENTRY abbrevid={{[0-9]+}} op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
; COMBINED-NEXT: </VALUE_SYMTAB
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -122,6 +122,7 @@ static const char *GetBlockName(unsigned BlockID,
case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
return "GLOBALVAL_SUMMARY_BLOCK"; return "GLOBALVAL_SUMMARY_BLOCK";
case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK"; case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK";
case bitc::STRTAB_BLOCK_ID: return "STRTAB_BLOCK";
} }
} }
@ -315,6 +316,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS) STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL) STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL) STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
STRINGIFY_CODE(FS, VALUE_GUID)
} }
case bitc::METADATA_ATTACHMENT_ID: case bitc::METADATA_ATTACHMENT_ID:
switch(CodeID) { switch(CodeID) {
@ -381,6 +383,11 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
default: return nullptr; default: return nullptr;
case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG"; case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG";
} }
case bitc::STRTAB_BLOCK_ID:
switch(CodeID) {
default: return nullptr;
case bitc::STRTAB_BLOB: return "BLOB";
}
} }
#undef STRINGIFY_CODE #undef STRINGIFY_CODE
} }

View File

@ -44,11 +44,16 @@ int main(int argc, char **argv) {
std::unique_ptr<MemoryBuffer> MB = ExitOnErr( std::unique_ptr<MemoryBuffer> MB = ExitOnErr(
errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename))); errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename)));
std::vector<BitcodeModule> Mods = ExitOnErr(getBitcodeModuleList(*MB)); std::vector<BitcodeModule> Mods = ExitOnErr(getBitcodeModuleList(*MB));
for (auto &BitcodeMod : Mods) for (auto &BitcodeMod : Mods) {
Buffer.insert(Buffer.end(), BitcodeMod.getBuffer().begin(), Buffer.insert(Buffer.end(), BitcodeMod.getBuffer().begin(),
BitcodeMod.getBuffer().end()); BitcodeMod.getBuffer().end());
Writer.copyStrtab(BitcodeMod.getStrtab());
}
} }
} else { } else {
// The string table does not own strings added to it, some of which are
// owned by the modules; keep them alive until we write the string table.
std::vector<std::unique_ptr<Module>> OwnedMods;
for (const auto &InputFilename : InputFilenames) { for (const auto &InputFilename : InputFilenames) {
SMDiagnostic Err; SMDiagnostic Err;
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context); std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
@ -57,7 +62,9 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
Writer.writeModule(M.get()); Writer.writeModule(M.get());
OwnedMods.push_back(std::move(M));
} }
Writer.writeStrtab();
} }
std::error_code EC; std::error_code EC;

View File

@ -59,9 +59,12 @@ int main(int argc, char **argv) {
ExitOnErr(errorCodeToError(EC)); ExitOnErr(errorCodeToError(EC));
if (BinaryExtract) { if (BinaryExtract) {
SmallVector<char, 0> Header; SmallVector<char, 0> Result;
BitcodeWriter Writer(Header); BitcodeWriter Writer(Result);
Out->os() << Header << Ms[ModuleIndex].getBuffer(); Result.append(Ms[ModuleIndex].getBuffer().begin(),
Ms[ModuleIndex].getBuffer().end());
Writer.copyStrtab(Ms[ModuleIndex].getStrtab());
Out->os() << Result;
Out->keep(); Out->keep();
return 0; return 0;
} }