mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-28 08:02:08 +00: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:
parent
dc77b2e960
commit
a0f371a106
@ -550,6 +550,8 @@ LLVM IR is defined with the following blocks:
|
||||
|
||||
* 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 Contents
|
||||
@ -577,7 +579,7 @@ MODULE_CODE_VERSION Record
|
||||
``[VERSION, version#]``
|
||||
|
||||
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
|
||||
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
|
||||
`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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -673,11 +681,14 @@ for each library name referenced.
|
||||
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
|
||||
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
|
||||
global variable
|
||||
|
||||
@ -755,11 +766,14 @@ global variable. The operand fields are:
|
||||
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
|
||||
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
|
||||
|
||||
* *callingconv*: The calling convention number:
|
||||
@ -817,11 +831,14 @@ function. The operand fields are:
|
||||
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
|
||||
fields are
|
||||
|
||||
* *strtab offset*, *strtab size*: Specifies the name of the alias.
|
||||
See `STRTAB_BLOCK Contents`_.
|
||||
|
||||
* *alias type*: The type index of the alias
|
||||
|
||||
* *aliasee val#*: The value index of the aliased value
|
||||
@ -1300,3 +1317,20 @@ METADATA_ATTACHMENT Contents
|
||||
----------------------------
|
||||
|
||||
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.
|
||||
|
@ -46,6 +46,9 @@ namespace llvm {
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
StringRef ModuleIdentifier;
|
||||
|
||||
// The string table used to interpret this module.
|
||||
StringRef Strtab;
|
||||
|
||||
// The bitstream location of the IDENTIFICATION_BLOCK.
|
||||
uint64_t IdentificationBit;
|
||||
|
||||
@ -70,6 +73,7 @@ namespace llvm {
|
||||
StringRef getBuffer() const {
|
||||
return StringRef((const char *)Buffer.begin(), Buffer.size());
|
||||
}
|
||||
StringRef getStrtab() const { return Strtab; }
|
||||
|
||||
StringRef getModuleIdentifier() const { return ModuleIdentifier; }
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_BITCODE_BITCODEWRITER_H
|
||||
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
@ -26,12 +27,25 @@ namespace llvm {
|
||||
SmallVectorImpl<char> &Buffer;
|
||||
std::unique_ptr<BitstreamWriter> Stream;
|
||||
|
||||
StringTableBuilder StrtabBuilder{StringTableBuilder::RAW};
|
||||
bool WroteStrtab = false;
|
||||
|
||||
void writeBlob(unsigned Block, unsigned Record, StringRef Blob);
|
||||
|
||||
public:
|
||||
/// Create a BitcodeWriter that writes to Buffer.
|
||||
BitcodeWriter(SmallVectorImpl<char> &Buffer);
|
||||
|
||||
~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.
|
||||
///
|
||||
/// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
namespace llvm {
|
||||
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 {
|
||||
// Blocks
|
||||
MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID,
|
||||
@ -52,7 +52,9 @@ enum BlockIDs {
|
||||
|
||||
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,
|
||||
@ -232,6 +234,10 @@ enum GlobalValueSummarySymtabCodes {
|
||||
// llvm.type.checked.load intrinsic with all constant integer arguments.
|
||||
// [typeid, offset, n x arg]
|
||||
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 {
|
||||
@ -550,6 +556,10 @@ enum ComdatSelectionKindCodes {
|
||||
COMDAT_SELECTION_KIND_SAME_SIZE = 5,
|
||||
};
|
||||
|
||||
enum StrtabCodes {
|
||||
STRTAB_BLOB = 1,
|
||||
};
|
||||
|
||||
} // End bitc namespace
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -372,15 +372,27 @@ Expected<std::string> readTriple(BitstreamCursor &Stream) {
|
||||
|
||||
class BitcodeReaderBase {
|
||||
protected:
|
||||
BitcodeReaderBase(BitstreamCursor Stream) : Stream(std::move(Stream)) {
|
||||
BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab)
|
||||
: Stream(std::move(Stream)), Strtab(Strtab) {
|
||||
this->Stream.setBlockInfo(&BlockInfo);
|
||||
}
|
||||
|
||||
BitstreamBlockInfo BlockInfo;
|
||||
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);
|
||||
|
||||
/// 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();
|
||||
|
||||
// Contains an arbitrary and optional string identifying the bitcode producer
|
||||
@ -402,11 +414,22 @@ BitcodeReaderBase::parseVersionRecord(ArrayRef<uint64_t> Record) {
|
||||
if (Record.size() < 1)
|
||||
return error("Invalid record");
|
||||
unsigned ModuleVersion = Record[0];
|
||||
if (ModuleVersion > 1)
|
||||
if (ModuleVersion > 2)
|
||||
return error("Invalid value");
|
||||
UseStrtab = ModuleVersion >= 2;
|
||||
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 {
|
||||
LLVMContext &Context;
|
||||
Module *TheModule = nullptr;
|
||||
@ -492,8 +515,8 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
|
||||
std::vector<std::string> BundleTags;
|
||||
|
||||
public:
|
||||
BitcodeReader(BitstreamCursor Stream, StringRef ProducerIdentification,
|
||||
LLVMContext &Context);
|
||||
BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
StringRef ProducerIdentification, LLVMContext &Context);
|
||||
|
||||
Error materializeForwardReferencedFunctions();
|
||||
|
||||
@ -628,7 +651,10 @@ private:
|
||||
|
||||
Expected<Value *> recordValue(SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned NameIndex, Triple &TT);
|
||||
void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F,
|
||||
ArrayRef<uint64_t> Record);
|
||||
Error parseValueSymbolTable(uint64_t Offset = 0);
|
||||
Error parseGlobalValueSymbolTable();
|
||||
Error parseConstants();
|
||||
Error rememberAndSkipFunctionBodies();
|
||||
Error rememberAndSkipFunctionBody();
|
||||
@ -681,12 +707,15 @@ class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase {
|
||||
std::string SourceFileName;
|
||||
|
||||
public:
|
||||
ModuleSummaryIndexBitcodeReader(
|
||||
BitstreamCursor Stream, ModuleSummaryIndex &TheIndex);
|
||||
ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
ModuleSummaryIndex &TheIndex);
|
||||
|
||||
Error parseModule(StringRef ModulePath);
|
||||
|
||||
private:
|
||||
void setValueGUID(uint64_t ValueID, StringRef ValueName,
|
||||
GlobalValue::LinkageTypes Linkage,
|
||||
StringRef SourceFileName);
|
||||
Error parseValueSymbolTable(
|
||||
uint64_t Offset,
|
||||
DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap);
|
||||
@ -716,10 +745,10 @@ std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
BitcodeReader::BitcodeReader(BitstreamCursor Stream,
|
||||
BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
StringRef ProducerIdentification,
|
||||
LLVMContext &Context)
|
||||
: BitcodeReaderBase(std::move(Stream)), Context(Context),
|
||||
: BitcodeReaderBase(std::move(Stream), Strtab), Context(Context),
|
||||
ValueList(Context) {
|
||||
this->ProducerIdentification = ProducerIdentification;
|
||||
}
|
||||
@ -1749,6 +1778,54 @@ static uint64_t jumpToValueSymbolTable(uint64_t Offset,
|
||||
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
|
||||
/// at the given bit offset if provided.
|
||||
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
|
||||
// VST (where we want to jump to the VST offset) and the function-level
|
||||
// VST (where we don't).
|
||||
if (Offset > 0)
|
||||
if (Offset > 0) {
|
||||
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
|
||||
// to the word-aligned ENTER_SUBBLOCK for the function block, and that
|
||||
@ -1818,23 +1905,10 @@ Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
|
||||
return Err;
|
||||
Value *V = ValOrErr.get();
|
||||
|
||||
auto *F = dyn_cast<Function>(V);
|
||||
// Ignore function offsets emitted for aliases of functions in older
|
||||
// versions of LLVM.
|
||||
if (!F)
|
||||
break;
|
||||
|
||||
// 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;
|
||||
if (auto *F = dyn_cast<Function>(V))
|
||||
setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record);
|
||||
break;
|
||||
}
|
||||
case bitc::VST_CODE_BBENTRY: {
|
||||
@ -2626,15 +2700,24 @@ bool BitcodeReaderBase::readBlockInfo() {
|
||||
}
|
||||
|
||||
Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
|
||||
// [selection_kind, name]
|
||||
if (Record.size() < 2)
|
||||
// v1: [selection_kind, name]
|
||||
// v2: [strtab_offset, strtab_size, selection_kind]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
if (Record.size() < 1)
|
||||
return error("Invalid record");
|
||||
Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]);
|
||||
std::string Name;
|
||||
unsigned ComdatNameSize = Record[1];
|
||||
Name.reserve(ComdatNameSize);
|
||||
for (unsigned i = 0; i != ComdatNameSize; ++i)
|
||||
Name += (char)Record[2 + i];
|
||||
std::string OldFormatName;
|
||||
if (!UseStrtab) {
|
||||
if (Record.size() < 2)
|
||||
return error("Invalid record");
|
||||
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);
|
||||
C->setSelectionKind(SK);
|
||||
ComdatList.push_back(C);
|
||||
@ -2642,9 +2725,13 @@ Error BitcodeReader::parseComdatRecord(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,
|
||||
// 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)
|
||||
return error("Invalid record");
|
||||
Type *Ty = getTypeByID(Record[0]);
|
||||
@ -2692,7 +2779,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||
ExternallyInitialized = Record[9];
|
||||
|
||||
GlobalVariable *NewGV =
|
||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "",
|
||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name,
|
||||
nullptr, TLM, AddressSpace, ExternallyInitialized);
|
||||
NewGV->setAlignment(Alignment);
|
||||
if (!Section.empty())
|
||||
@ -2724,9 +2811,13 @@ Error BitcodeReader::parseGlobalVarRecord(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,
|
||||
// prefixdata]
|
||||
// prefixdata] (name in VST)
|
||||
// v2: [strtab_offset, strtab_size, v1]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
if (Record.size() < 8)
|
||||
return error("Invalid record");
|
||||
Type *Ty = getTypeByID(Record[0]);
|
||||
@ -2742,7 +2833,7 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
return error("Invalid calling convention ID");
|
||||
|
||||
Function *Func =
|
||||
Function::Create(FTy, GlobalValue::ExternalLinkage, "", TheModule);
|
||||
Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule);
|
||||
|
||||
Func->setCallingConv(CC);
|
||||
bool isProto = Record[2];
|
||||
@ -2810,11 +2901,15 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
|
||||
Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
unsigned BitCode, ArrayRef<uint64_t> Record) {
|
||||
// ALIAS_OLD: [alias type, aliasee val#, linkage]
|
||||
// ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
|
||||
// dllstorageclass]
|
||||
// IFUNC: [alias type, addrspace, aliasee val#, linkage,
|
||||
// visibility, dllstorageclass]
|
||||
// v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST)
|
||||
// v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
|
||||
// dllstorageclass] (name in VST)
|
||||
// v1 IFUNC: [alias type, addrspace, aliasee val#, linkage,
|
||||
// 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;
|
||||
if (Record.size() < (3 + (unsigned)NewRecord))
|
||||
return error("Invalid record");
|
||||
@ -2839,10 +2934,10 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
GlobalIndirectSymbol *NewGA;
|
||||
if (BitCode == bitc::MODULE_CODE_ALIAS ||
|
||||
BitCode == bitc::MODULE_CODE_ALIAS_OLD)
|
||||
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "",
|
||||
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
|
||||
TheModule);
|
||||
else
|
||||
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "",
|
||||
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
|
||||
nullptr, TheModule);
|
||||
// Old bitcode files didn't have visibility field.
|
||||
// Local linkage must have default visibility.
|
||||
@ -4570,8 +4665,8 @@ std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const {
|
||||
}
|
||||
|
||||
ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader(
|
||||
BitstreamCursor Cursor, ModuleSummaryIndex &TheIndex)
|
||||
: BitcodeReaderBase(std::move(Cursor)), TheIndex(TheIndex) {}
|
||||
BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex)
|
||||
: BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex) {}
|
||||
|
||||
std::pair<GlobalValue::GUID, GlobalValue::GUID>
|
||||
ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
|
||||
@ -4580,12 +4675,32 @@ ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
|
||||
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
|
||||
// blocks where we don't actually create global values. The parsed information
|
||||
// is saved in the bitcode reader for use when later parsing summaries.
|
||||
Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
uint64_t Offset,
|
||||
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");
|
||||
uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream);
|
||||
|
||||
@ -4627,17 +4742,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
assert(VLI != ValueIdToLinkageMap.end() &&
|
||||
"No linkage found for VST entry?");
|
||||
auto Linkage = VLI->second;
|
||||
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);
|
||||
setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
|
||||
ValueName.clear();
|
||||
break;
|
||||
}
|
||||
@ -4651,18 +4756,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
assert(VLI != ValueIdToLinkageMap.end() &&
|
||||
"No linkage found for VST entry?");
|
||||
auto Linkage = VLI->second;
|
||||
std::string FunctionGlobalId = GlobalValue::getGlobalIdentifier(
|
||||
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);
|
||||
|
||||
setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
|
||||
ValueName.clear();
|
||||
break;
|
||||
}
|
||||
@ -4749,6 +4843,11 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
|
||||
switch (BitCode) {
|
||||
default:
|
||||
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]
|
||||
case bitc::MODULE_CODE_SOURCE_FILENAME: {
|
||||
SmallString<128> ValueName;
|
||||
@ -4783,17 +4882,26 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
|
||||
// was historically always the start of the regular bitcode header.
|
||||
VSTOffset = Record[0] - 1;
|
||||
break;
|
||||
// GLOBALVAR: [pointer type, isconst, initid, linkage, ...]
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, ...]
|
||||
// ALIAS: [alias type, addrspace, aliasee val#, linkage, ...]
|
||||
// v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...]
|
||||
// v1 FUNCTION: [type, callingconv, isproto, linkage, ...]
|
||||
// v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...]
|
||||
// v2: [strtab offset, strtab size, v1]
|
||||
case bitc::MODULE_CODE_GLOBALVAR:
|
||||
case bitc::MODULE_CODE_FUNCTION:
|
||||
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");
|
||||
uint64_t RawLinkage = Record[3];
|
||||
uint64_t RawLinkage = GVRecord[3];
|
||||
GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
|
||||
ValueIdToLinkageMap[ValueId++] = Linkage;
|
||||
if (!UseStrtab) {
|
||||
ValueIdToLinkageMap[ValueId++] = Linkage;
|
||||
break;
|
||||
}
|
||||
|
||||
setValueGUID(ValueId++, Name, Linkage, SourceFileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -4904,6 +5012,12 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(
|
||||
switch (BitCode) {
|
||||
default: // Default behavior: ignore.
|
||||
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,
|
||||
// n x (valueid)]
|
||||
// FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs,
|
||||
@ -5208,6 +5322,35 @@ const std::error_category &llvm::BitcodeErrorCategory() {
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -5260,6 +5403,22 @@ llvm::getBitcodeModuleList(MemoryBufferRef Buffer) {
|
||||
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())
|
||||
return error("Malformed block");
|
||||
continue;
|
||||
@ -5296,8 +5455,8 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
|
||||
}
|
||||
|
||||
Stream.JumpToBit(ModuleBit);
|
||||
auto *R =
|
||||
new BitcodeReader(std::move(Stream), ProducerIdentification, Context);
|
||||
auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification,
|
||||
Context);
|
||||
|
||||
std::unique_ptr<Module> M =
|
||||
llvm::make_unique<Module>(ModuleIdentifier, Context);
|
||||
@ -5332,7 +5491,7 @@ Expected<std::unique_ptr<ModuleSummaryIndex>> BitcodeModule::getSummary() {
|
||||
Stream.JumpToBit(ModuleBit);
|
||||
|
||||
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))
|
||||
return std::move(Err);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/UseListOrder.h"
|
||||
#include "llvm/IR/ValueSymbolTable.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
@ -76,26 +77,28 @@ protected:
|
||||
/// The stream created and owned by the client.
|
||||
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:
|
||||
/// Constructs a BitcodeWriterBase object that writes to the provided
|
||||
/// \p Stream.
|
||||
BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {}
|
||||
|
||||
protected:
|
||||
bool hasVSTOffsetPlaceholder() { return VSTOffsetPlaceholder != 0; }
|
||||
void writeValueSymbolTableForwardDecl();
|
||||
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 ModuleBitcodeWriter : public BitcodeWriterBase {
|
||||
/// Pointer to the buffer allocated by caller for bitcode writing.
|
||||
const SmallVectorImpl<char> &Buffer;
|
||||
|
||||
StringTableBuilder &StrtabBuilder;
|
||||
|
||||
/// The Module to write to bitcode.
|
||||
const Module &M;
|
||||
|
||||
@ -127,15 +130,20 @@ class ModuleBitcodeWriter : public BitcodeWriterBase {
|
||||
/// Tracks the last value id recorded in the GUIDToValueMap.
|
||||
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:
|
||||
/// Constructs a ModuleBitcodeWriter object for the given Module,
|
||||
/// writing to the provided \p Buffer.
|
||||
ModuleBitcodeWriter(const Module *M, SmallVectorImpl<char> &Buffer,
|
||||
StringTableBuilder &StrtabBuilder,
|
||||
BitstreamWriter &Stream, bool ShouldPreserveUseListOrder,
|
||||
const ModuleSummaryIndex *Index, bool GenerateHash,
|
||||
ModuleHash *ModHash = nullptr)
|
||||
: BitcodeWriterBase(Stream), Buffer(Buffer), M(*M),
|
||||
VE(*M, ShouldPreserveUseListOrder), Index(Index),
|
||||
: BitcodeWriterBase(Stream), Buffer(Buffer), StrtabBuilder(StrtabBuilder),
|
||||
M(*M), VE(*M, ShouldPreserveUseListOrder), Index(Index),
|
||||
GenerateHash(GenerateHash), ModHash(ModHash),
|
||||
BitcodeStartBit(Stream.GetCurrentBitNo()) {
|
||||
// Assign ValueIds to any callee values in the index that came from
|
||||
@ -169,6 +177,7 @@ private:
|
||||
void writeAttributeTable();
|
||||
void writeTypeTable();
|
||||
void writeComdats();
|
||||
void writeValueSymbolTableForwardDecl();
|
||||
void writeModuleInfo();
|
||||
void writeValueAsMetadata(const ValueAsMetadata *MD,
|
||||
SmallVectorImpl<uint64_t> &Record);
|
||||
@ -261,9 +270,9 @@ private:
|
||||
SmallVectorImpl<uint64_t> &Vals);
|
||||
void writeInstruction(const Instruction &I, unsigned InstID,
|
||||
SmallVectorImpl<unsigned> &Vals);
|
||||
void writeValueSymbolTable(
|
||||
const ValueSymbolTable &VST, bool IsModuleLevel = false,
|
||||
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex = nullptr);
|
||||
void writeFunctionLevelValueSymbolTable(const ValueSymbolTable &VST);
|
||||
void writeGlobalValueSymbolTable(
|
||||
DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex);
|
||||
void writeUseList(UseListOrder &&Order);
|
||||
void writeUseListBlock(const Function *F);
|
||||
void
|
||||
@ -477,7 +486,6 @@ public:
|
||||
|
||||
private:
|
||||
void writeModStrings();
|
||||
void writeCombinedValueSymbolTable();
|
||||
void writeCombinedGlobalValueSummary();
|
||||
|
||||
/// Indicates whether the provided \p ModulePath should be written into
|
||||
@ -492,15 +500,15 @@ private:
|
||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
return VMI != GUIDToValueIdMap.end();
|
||||
}
|
||||
void assignValueId(GlobalValue::GUID ValGUID) {
|
||||
unsigned &ValueId = GUIDToValueIdMap[ValGUID];
|
||||
if (ValueId == 0)
|
||||
ValueId = ++GlobalValueId;
|
||||
}
|
||||
unsigned getValueId(GlobalValue::GUID ValGUID) {
|
||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
// If this GUID doesn't have an entry, assign one.
|
||||
if (VMI == GUIDToValueIdMap.end()) {
|
||||
GUIDToValueIdMap[ValGUID] = ++GlobalValueId;
|
||||
return GlobalValueId;
|
||||
} else {
|
||||
return VMI->second;
|
||||
}
|
||||
auto VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
assert(VMI != GUIDToValueIdMap.end());
|
||||
return VMI->second;
|
||||
}
|
||||
std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; }
|
||||
};
|
||||
@ -1047,13 +1055,10 @@ static unsigned getEncodedUnnamedAddr(const GlobalValue &GV) {
|
||||
void ModuleBitcodeWriter::writeComdats() {
|
||||
SmallVector<unsigned, 64> Vals;
|
||||
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));
|
||||
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);
|
||||
Vals.clear();
|
||||
}
|
||||
@ -1062,7 +1067,7 @@ void ModuleBitcodeWriter::writeComdats() {
|
||||
/// 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
|
||||
/// 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,
|
||||
// which is written after the function blocks so that it can include
|
||||
// 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.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
||||
Log2_32_Ceil(MaxGlobalType+1)));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2
|
||||
@ -1188,15 +1195,42 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
}
|
||||
|
||||
// Emit the global variable information.
|
||||
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()) {
|
||||
unsigned AbbrevToUse = 0;
|
||||
|
||||
// GLOBALVAR: [type, isconst, initid,
|
||||
// GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
|
||||
// linkage, alignment, section, visibility, threadlocal,
|
||||
// unnamed_addr, externally_initialized, dllstorageclass,
|
||||
// comdat]
|
||||
Vals.push_back(StrtabBuilder.add(GV.getName()));
|
||||
Vals.push_back(GV.getName().size());
|
||||
Vals.push_back(VE.getTypeID(GV.getValueType()));
|
||||
Vals.push_back(GV.getType()->getAddressSpace() << 2 | 2 | GV.isConstant());
|
||||
Vals.push_back(GV.isDeclaration() ? 0 :
|
||||
@ -1226,9 +1260,12 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the function proto information.
|
||||
for (const Function &F : M) {
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment,
|
||||
// section, visibility, gc, unnamed_addr, prologuedata,
|
||||
// dllstorageclass, comdat, prefixdata, personalityfn]
|
||||
// FUNCTION: [strtab offset, strtab size, type, callingconv, isproto,
|
||||
// linkage, paramattrs, alignment, section, visibility, gc,
|
||||
// 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(F.getCallingConv());
|
||||
Vals.push_back(F.isDeclaration());
|
||||
@ -1255,8 +1292,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the alias information.
|
||||
for (const GlobalAlias &A : M.aliases()) {
|
||||
// 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]
|
||||
Vals.push_back(StrtabBuilder.add(A.getName()));
|
||||
Vals.push_back(A.getName().size());
|
||||
Vals.push_back(VE.getTypeID(A.getValueType()));
|
||||
Vals.push_back(A.getType()->getAddressSpace());
|
||||
Vals.push_back(VE.getValueID(A.getAliasee()));
|
||||
@ -1272,7 +1311,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the ifunc information.
|
||||
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(I.getType()->getAddressSpace());
|
||||
Vals.push_back(VE.getValueID(I.getResolver()));
|
||||
@ -1282,34 +1324,6 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -2839,78 +2853,60 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
||||
Vals.clear();
|
||||
}
|
||||
|
||||
/// Emit names for globals/functions etc. \p IsModuleLevel is true when
|
||||
/// we are writing the module-level VST, where we are including a function
|
||||
/// bitcode index and need to backpatch the VST forward declaration record.
|
||||
void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
const ValueSymbolTable &VST, bool IsModuleLevel,
|
||||
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex) {
|
||||
if (VST.empty()) {
|
||||
// writeValueSymbolTableForwardDecl should have returned early as
|
||||
// well. Ensure this handling remains in sync by asserting that
|
||||
// the placeholder offset is not set.
|
||||
assert(!IsModuleLevel || !hasVSTOffsetPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
/// Write a GlobalValue VST to the module. The purpose of this data structure is
|
||||
/// to allow clients to efficiently find the function body.
|
||||
void ModuleBitcodeWriter::writeGlobalValueSymbolTable(
|
||||
DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex) {
|
||||
// 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);
|
||||
|
||||
// For the module-level VST, add abbrev Ids for the VST_CODE_FNENTRY
|
||||
// records, which are not used in the per-function VSTs.
|
||||
unsigned FnEntry8BitAbbrev;
|
||||
unsigned FnEntry7BitAbbrev;
|
||||
unsigned FnEntry6BitAbbrev;
|
||||
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));
|
||||
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
|
||||
unsigned FnEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
// 7-bit fixed width VST_CODE_FNENTRY function strings.
|
||||
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, 7));
|
||||
FnEntry7BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
for (const Function &F : M) {
|
||||
uint64_t Record[2];
|
||||
|
||||
// 6-bit char6 VST_CODE_FNENTRY function strings.
|
||||
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::Char6));
|
||||
FnEntry6BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
||||
// FIXME: Change the name of this record as it is now used by
|
||||
// the per-module index as well.
|
||||
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
|
||||
GUIDEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
Record[0] = VE.getValueID(&F);
|
||||
|
||||
// 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.
|
||||
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: We know if the type names can use 7-bit ascii.
|
||||
SmallVector<uint64_t, 64> NameVals;
|
||||
@ -2923,38 +2919,13 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
unsigned AbbrevToUse = VST_ENTRY_8_ABBREV;
|
||||
NameVals.push_back(VE.getValueID(Name.getValue()));
|
||||
|
||||
Function *F = dyn_cast<Function>(Name.getValue());
|
||||
|
||||
// VST_CODE_ENTRY: [valueid, namechar x N]
|
||||
// VST_CODE_FNENTRY: [valueid, funcoffset, namechar x N]
|
||||
// VST_CODE_BBENTRY: [bbid, namechar x N]
|
||||
unsigned Code;
|
||||
if (isa<BasicBlock>(Name.getValue())) {
|
||||
Code = bitc::VST_CODE_BBENTRY;
|
||||
if (Bits == SE_Char6)
|
||||
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 {
|
||||
Code = bitc::VST_CODE_ENTRY;
|
||||
if (Bits == SE_Char6)
|
||||
@ -2970,47 +2941,7 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
Stream.EmitRecord(Code, NameVals, AbbrevToUse);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -3114,7 +3045,7 @@ void ModuleBitcodeWriter::writeFunction(
|
||||
|
||||
// Emit names for all the instructions etc.
|
||||
if (auto *Symtab = F.getValueSymbolTable())
|
||||
writeValueSymbolTable(*Symtab);
|
||||
writeFunctionLevelValueSymbolTable(*Symtab);
|
||||
|
||||
if (NeedsMetadataAttachment)
|
||||
writeFunctionMetadataAttachment(F);
|
||||
@ -3502,6 +3433,11 @@ void ModuleBitcodeWriter::writePerModuleGlobalValueSummary() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &GVI : valueIds()) {
|
||||
Stream.EmitRecord(bitc::FS_VALUE_GUID,
|
||||
ArrayRef<uint64_t>{GVI.second, GVI.first});
|
||||
}
|
||||
|
||||
// Abbrev for FS_PERMODULE.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE));
|
||||
@ -3594,6 +3530,39 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3);
|
||||
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.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_COMBINED));
|
||||
@ -3808,10 +3777,7 @@ void ModuleBitcodeWriter::write() {
|
||||
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
|
||||
size_t BlockStartPos = Buffer.size();
|
||||
|
||||
SmallVector<unsigned, 1> Vals;
|
||||
unsigned CurVersion = 1;
|
||||
Vals.push_back(CurVersion);
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals);
|
||||
writeModuleVersion();
|
||||
|
||||
// Emit blockinfo, which defines the standard abbreviations etc.
|
||||
writeBlockInfo();
|
||||
@ -3857,8 +3823,7 @@ void ModuleBitcodeWriter::write() {
|
||||
if (Index)
|
||||
writePerModuleGlobalValueSummary();
|
||||
|
||||
writeValueSymbolTable(M.getValueSymbolTable(),
|
||||
/* IsModuleLevel */ true, &FunctionToBitcodeIndex);
|
||||
writeGlobalValueSymbolTable(FunctionToBitcodeIndex);
|
||||
|
||||
writeModuleHash(BlockStartPos);
|
||||
|
||||
@ -3946,13 +3911,45 @@ BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer)
|
||||
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,
|
||||
bool ShouldPreserveUseListOrder,
|
||||
const ModuleSummaryIndex *Index,
|
||||
bool GenerateHash, ModuleHash *ModHash) {
|
||||
ModuleBitcodeWriter ModuleWriter(M, Buffer, *Stream,
|
||||
ModuleBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream,
|
||||
ShouldPreserveUseListOrder, Index,
|
||||
GenerateHash, ModHash);
|
||||
ModuleWriter.write();
|
||||
@ -3976,6 +3973,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
BitcodeWriter Writer(Buffer);
|
||||
Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash,
|
||||
ModHash);
|
||||
Writer.writeStrtab();
|
||||
|
||||
if (TT.isOSDarwin() || TT.isOSBinFormatMachO())
|
||||
emitDarwinBCHeaderAndTrailer(Buffer, TT);
|
||||
@ -3987,13 +3985,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
void IndexBitcodeWriter::write() {
|
||||
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
|
||||
|
||||
SmallVector<unsigned, 1> Vals;
|
||||
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();
|
||||
writeModuleVersion();
|
||||
|
||||
// Write the module paths in the combined index.
|
||||
writeModStrings();
|
||||
@ -4001,10 +3993,6 @@ void IndexBitcodeWriter::write() {
|
||||
// Write the summary combined index records.
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -363,6 +363,7 @@ void splitAndWriteThinLTOBitcode(
|
||||
W.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index,
|
||||
/*GenerateHash=*/true, &ModHash);
|
||||
W.writeModule(MergedM.get());
|
||||
W.writeStrtab();
|
||||
OS << Buffer;
|
||||
|
||||
// If a minimized bitcode module was requested for the thin link,
|
||||
@ -375,6 +376,7 @@ void splitAndWriteThinLTOBitcode(
|
||||
W2.writeModule(&M, /*ShouldPreserveUseListOrder=*/false, &Index,
|
||||
/*GenerateHash=*/false, &ModHash);
|
||||
W2.writeModule(MergedM.get());
|
||||
W2.writeStrtab();
|
||||
*ThinLinkOS << Buffer;
|
||||
}
|
||||
}
|
||||
|
@ -5,33 +5,31 @@
|
||||
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
|
||||
; 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-NEXT: <VERSION
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and value id matching the subsequent value symbol table.
|
||||
; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/>
|
||||
; See if the call to func is registered.
|
||||
; The value id 1 matches the second FUNCTION record above.
|
||||
; CHECK-NEXT: <PERMODULE {{.*}} op4=1/>
|
||||
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
|
||||
; CHECK-NEXT: <VALUE_SYMTAB
|
||||
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
|
||||
; External function analias should have entry with value id FUNCID
|
||||
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'analias'
|
||||
; CHECK-NEXT: </VALUE_SYMTAB>
|
||||
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'mainanalias'
|
||||
|
||||
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; COMBINED-NEXT: <VERSION
|
||||
; See if the call to analias is registered, using the expected callsite count
|
||||
; and value id matching the subsequent value symbol table.
|
||||
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID:[0-9]+]]/>
|
||||
; Followed by the alias and aliasee
|
||||
; See if the call to analias is registered, using the expected value id.
|
||||
; COMBINED-NEXT: <VALUE_GUID op0=[[ALIASID:[0-9]+]] op1=-5751648690987223394/>
|
||||
; COMBINED-NEXT: <VALUE_GUID
|
||||
; COMBINED-NEXT: <VALUE_GUID op0=[[ALIASEEID:[0-9]+]] op1=-1039159065113703048/>
|
||||
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID]]/>
|
||||
; COMBINED-NEXT: <COMBINED {{.*}}
|
||||
; COMBINED-NEXT: <COMBINED_ALIAS {{.*}} op3=[[ALIASEEID:[0-9]+]]
|
||||
; COMBINED-NEXT: <COMBINED_ALIAS {{.*}} op3=[[ALIASEEID]]
|
||||
; 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'
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -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-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-NEXT: <VERSION
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and hotness type, with value id matching the subsequent value symbol table.
|
||||
; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[FUNCID:[0-9]+]] op5=2/>
|
||||
; See if the call to func is registered, using the expected hotness type.
|
||||
; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=1 op5=2/>
|
||||
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
|
||||
; CHECK-NEXT: <VALUE_SYMTAB
|
||||
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
|
||||
; External function func should have entry with value id FUNCID
|
||||
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'func'
|
||||
; CHECK-NEXT: </VALUE_SYMTAB>
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'mainfunc'
|
||||
|
||||
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; COMBINED-NEXT: <VERSION
|
||||
; COMBINED-NEXT: <VALUE_GUID op0=[[FUNCID:[0-9]+]] op1=7289175272376759421/>
|
||||
; COMBINED-NEXT: <VALUE_GUID
|
||||
; COMBINED-NEXT: <COMBINED
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and hotness type, with value id matching the subsequent value symbol table.
|
||||
; See if the call to func is registered, using the expected hotness type.
|
||||
; 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: <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'
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -6,27 +6,45 @@
|
||||
; 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-NEXT: <VERSION
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and profile count, with value id matching the subsequent value symbol table.
|
||||
; 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: <VALUE_GUID op0=25 op1=123/>
|
||||
; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123
|
||||
; 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-LABEL: <VALUE_SYMTAB
|
||||
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'hot_function
|
||||
; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE1]] {{.*}} record string = 'none1'
|
||||
; 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>
|
||||
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'hot_functionhot1hot2hot3hot4coldnone1none2none3'
|
||||
|
||||
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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=
|
||||
|
@ -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-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-NEXT: <VERSION
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and value id matching the subsequent value symbol table.
|
||||
; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/>
|
||||
; See if the call to func is registered.
|
||||
; CHECK-NEXT: <PERMODULE {{.*}} op4=1/>
|
||||
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
|
||||
; CHECK-NEXT: <VALUE_SYMTAB
|
||||
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
|
||||
; External function func should have entry with value id FUNCID
|
||||
; CHECK-NEXT: <ENTRY {{.*}} op0=[[FUNCID]] {{.*}} record string = 'func'
|
||||
; CHECK-NEXT: </VALUE_SYMTAB>
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'mainfunc'
|
||||
|
||||
|
||||
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; COMBINED-NEXT: <VERSION
|
||||
; COMBINED-NEXT: <VALUE_GUID op0=[[FUNCID:[0-9]+]] op1=7289175272376759421/>
|
||||
; COMBINED-NEXT: <VALUE_GUID
|
||||
; COMBINED-NEXT: <COMBINED
|
||||
; See if the call to func is registered, using the expected callsite count
|
||||
; and value id matching the subsequent value symbol table.
|
||||
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID:[0-9]+]]/>
|
||||
; See if the call to func is registered.
|
||||
; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID]]/>
|
||||
; 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'
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
@ -49,4 +46,4 @@ entry:
|
||||
declare void @func(...) #1
|
||||
|
||||
; OLD: Index {{.*}} contains 1 nodes (1 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
|
||||
; OLD-COMBINED: Index {{.*}} contains 2 nodes (2 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
|
||||
; OLD-COMBINED: Index {{.*}} contains 2 nodes (2 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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_ORIGINAL_NAME op0=6699318081062747564/>
|
||||
; COMBINED-DAG: <COMBINED_GLOBALVAR_INIT_REFS
|
||||
@ -12,11 +15,6 @@
|
||||
; COMBINED-DAG: <COMBINED_ALIAS
|
||||
; COMBINED-DAG: <COMBINED_ORIGINAL_NAME op0=-4170563161550796836/>
|
||||
; 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"
|
||||
|
||||
|
@ -2,6 +2,32 @@
|
||||
; RUN: opt -module-summary %s -o %t.o
|
||||
; 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
|
||||
; expected value id and other information as appropriate (callsite cout
|
||||
; for calls). Use different linkage types for the various test cases to
|
||||
@ -11,37 +37,32 @@
|
||||
; llvm.ctpop.i8.
|
||||
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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:
|
||||
; 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
|
||||
; 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
|
||||
; a reference to it when reached while earlier analyzing the phi using its
|
||||
; 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
|
||||
; a reference to it when reached while analyzing subsequent use of its return
|
||||
; 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:
|
||||
; 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-NEXT: <VALUE_SYMTAB
|
||||
; CHECK-DAG: <ENTRY {{.*}} op0=[[BARID]] {{.*}} record string = 'bar'
|
||||
; 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>
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'barglobalvarfuncfunc2foofunc3WXYZllvm.ctpop.i8main'
|
||||
|
||||
; ModuleID = 'thinlto-function-summary-refgraph.ll'
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,9 +2,19 @@
|
||||
; RUN: opt -passes=name-anon-globals -module-summary < %s | llvm-bcanalyzer -dump | FileCheck %s -check-prefix=BC
|
||||
; Check for summary block/records.
|
||||
|
||||
; Check the value ids in the summary entries against the
|
||||
; same in the ValueSumbolTable, to ensure the ordering is stable.
|
||||
; Also check the linkage field on the summary entries.
|
||||
; BC: <SOURCE_FILENAME
|
||||
; "h"
|
||||
; 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-NEXT: <VERSION
|
||||
; BC-NEXT: <PERMODULE {{.*}} op0=1 op1=0
|
||||
@ -13,13 +23,8 @@
|
||||
; BC-NEXT: <PERMODULE {{.*}} op0=4 op1=16
|
||||
; BC-NEXT: <ALIAS {{.*}} op0=5 op1=0 op2=3
|
||||
; BC-NEXT: </GLOBALVAL_SUMMARY_BLOCK
|
||||
; BC-NEXT: <VALUE_SYMTAB
|
||||
; BC-NEXT: <FNENTRY {{.*}} op0=4 {{.*}}> record string = 'variadic'
|
||||
; 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.
|
||||
; BC: <STRTAB_BLOCK
|
||||
; BC-NEXT: blob data = 'hfoobaranon.{{................................}}.0variadicf'
|
||||
|
||||
|
||||
; RUN: opt -name-anon-globals -module-summary < %s | llvm-dis | FileCheck %s
|
||||
|
@ -9,10 +9,8 @@
|
||||
; RUN: -import=globalfunc1:%p/Inputs/autoupgrade.bc %t.bc \
|
||||
; RUN: | llvm-bcanalyzer -dump | FileCheck %s
|
||||
|
||||
|
||||
; CHECK-NOT: 'llvm.invariant.start'
|
||||
; CHECK: record string = 'llvm.invariant.start.p0i8'
|
||||
; CHECK-NOT: 'llvm.invariant.start'
|
||||
; CHECK: <STRTAB_BLOCK
|
||||
; CHECK-NEXT: blob data = 'mainglobalfunc1llvm.invariant.start.p0i8'
|
||||
|
||||
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-apple-macosx10.11.0"
|
||||
|
@ -13,15 +13,11 @@
|
||||
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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: </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
|
||||
; itself only, as it does not import anything.
|
||||
@ -30,13 +26,9 @@
|
||||
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; BACKEND2-NEXT: <VERSION
|
||||
; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
|
||||
; BACKEND2-NEXT: <COMBINED
|
||||
; 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(...)
|
||||
|
||||
|
@ -82,15 +82,11 @@
|
||||
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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: </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,
|
||||
; as it does not import anything.
|
||||
@ -99,13 +95,9 @@
|
||||
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; BACKEND2-NEXT: <VERSION
|
||||
; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
|
||||
; BACKEND2-NEXT: <COMBINED
|
||||
; 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-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
||||
@ -113,15 +105,11 @@
|
||||
; COMBINED-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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: </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 triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -11,15 +11,11 @@
|
||||
; COMBINED-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; COMBINED-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; 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: </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"
|
||||
|
||||
|
@ -122,6 +122,7 @@ static const char *GetBlockName(unsigned BlockID,
|
||||
case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
|
||||
return "GLOBALVAL_SUMMARY_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_TEST_ASSUME_CONST_VCALL)
|
||||
STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
|
||||
STRINGIFY_CODE(FS, VALUE_GUID)
|
||||
}
|
||||
case bitc::METADATA_ATTACHMENT_ID:
|
||||
switch(CodeID) {
|
||||
@ -381,6 +383,11 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
default: return nullptr;
|
||||
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
|
||||
}
|
||||
|
@ -44,11 +44,16 @@ int main(int argc, char **argv) {
|
||||
std::unique_ptr<MemoryBuffer> MB = ExitOnErr(
|
||||
errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename)));
|
||||
std::vector<BitcodeModule> Mods = ExitOnErr(getBitcodeModuleList(*MB));
|
||||
for (auto &BitcodeMod : Mods)
|
||||
for (auto &BitcodeMod : Mods) {
|
||||
Buffer.insert(Buffer.end(), BitcodeMod.getBuffer().begin(),
|
||||
BitcodeMod.getBuffer().end());
|
||||
Writer.copyStrtab(BitcodeMod.getStrtab());
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
|
||||
@ -57,7 +62,9 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
Writer.writeModule(M.get());
|
||||
OwnedMods.push_back(std::move(M));
|
||||
}
|
||||
Writer.writeStrtab();
|
||||
}
|
||||
|
||||
std::error_code EC;
|
||||
|
@ -59,9 +59,12 @@ int main(int argc, char **argv) {
|
||||
ExitOnErr(errorCodeToError(EC));
|
||||
|
||||
if (BinaryExtract) {
|
||||
SmallVector<char, 0> Header;
|
||||
BitcodeWriter Writer(Header);
|
||||
Out->os() << Header << Ms[ModuleIndex].getBuffer();
|
||||
SmallVector<char, 0> Result;
|
||||
BitcodeWriter Writer(Result);
|
||||
Result.append(Ms[ModuleIndex].getBuffer().begin(),
|
||||
Ms[ModuleIndex].getBuffer().end());
|
||||
Writer.copyStrtab(Ms[ModuleIndex].getStrtab());
|
||||
Out->os() << Result;
|
||||
Out->keep();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user