Support for function summary index bitcode sections and files.

Summary:
The bitcode format is described in this document:
  https://drive.google.com/file/d/0B036uwnWM6RWdnBLakxmeDdOeXc/view
For more info on ThinLTO see:
  https://sites.google.com/site/llvmthinlto

The first customer is ThinLTO, however the data structures are designed
and named more generally based on prior feedback. There are a few
comments regarding how certain interfaces are used by ThinLTO, and the
options added here to gold currently have ThinLTO-specific names as the
behavior they provoke is currently ThinLTO-specific.

This patch includes support for generating per-module function indexes,
the combined index file via the gold plugin, and several tests
(more are included with the associated clang patch D11908).

Reviewers: dexonsmith, davidxl, joker.eph

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D13107

llvm-svn: 249270
This commit is contained in:
Teresa Johnson
2015-10-04 14:33:43 +00:00
parent d78616f98a
commit 403a787e03
20 changed files with 1633 additions and 46 deletions

View File

@@ -13,6 +13,7 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "ValueEnumerator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Bitcode/LLVMBitCodes.h"
@@ -23,6 +24,7 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/UseListOrder.h"
@@ -2187,7 +2189,8 @@ static void WriteValueSymbolTable(
const ValueSymbolTable &VST, const ValueEnumerator &VE,
BitstreamWriter &Stream, uint64_t VSTOffsetPlaceholder = 0,
uint64_t BitcodeStartBit = 0,
DenseMap<const Function *, uint64_t> *FunctionIndex = nullptr) {
DenseMap<const Function *, std::unique_ptr<FunctionInfo>> *FunctionIndex =
nullptr) {
if (VST.empty()) {
// WriteValueSymbolTableForwardDecl should have returned early as
// well. Ensure this handling remains in sync by asserting that
@@ -2282,7 +2285,8 @@ static void WriteValueSymbolTable(
// Save the word offset of the function (from the start of the
// actual bitcode written to the stream).
assert(FunctionIndex->count(F) == 1);
uint64_t BitcodeIndex = (*FunctionIndex)[F] - BitcodeStartBit;
uint64_t BitcodeIndex =
(*FunctionIndex)[F]->bitcodeIndex() - BitcodeStartBit;
assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
NameVals.push_back(BitcodeIndex / 32);
@@ -2300,9 +2304,7 @@ static void WriteValueSymbolTable(
AbbrevToUse = VST_ENTRY_7_ABBREV;
}
for (const char *P = Name.getKeyData(),
*E = Name.getKeyData()+Name.getKeyLength(); P != E; ++P)
NameVals.push_back((unsigned char)*P);
for (const auto P : Name.getKey()) NameVals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(Code, NameVals, AbbrevToUse);
@@ -2311,6 +2313,68 @@ static void WriteValueSymbolTable(
Stream.ExitBlock();
}
/// Emit function names and summary offsets for the combined index
/// used by ThinLTO.
static void WriteCombinedValueSymbolTable(const FunctionInfoIndex *Index,
BitstreamWriter &Stream) {
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
// 8-bit fixed-width VST_COMBINED_FNENTRY function strings.
BitCodeAbbrev *Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_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));
unsigned FnEntry8BitAbbrev = Stream.EmitAbbrev(Abbv);
// 7-bit fixed width VST_COMBINED_FNENTRY function strings.
Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_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));
unsigned FnEntry7BitAbbrev = Stream.EmitAbbrev(Abbv);
// 6-bit char6 VST_COMBINED_FNENTRY function strings.
Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_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));
unsigned FnEntry6BitAbbrev = Stream.EmitAbbrev(Abbv);
// FIXME: We know if the type names can use 7-bit ascii.
SmallVector<unsigned, 64> NameVals;
for (const auto &FII : *Index) {
for (const auto &FI : FII.getValue()) {
NameVals.push_back(FI->bitcodeIndex());
StringRef FuncName = FII.first();
// Figure out the encoding to use for the name.
StringEncoding Bits = getStringEncoding(FuncName.data(), FuncName.size());
// VST_COMBINED_FNENTRY: [funcsumoffset, namechar x N]
unsigned AbbrevToUse = FnEntry8BitAbbrev;
if (Bits == SE_Char6)
AbbrevToUse = FnEntry6BitAbbrev;
else if (Bits == SE_Fixed7)
AbbrevToUse = FnEntry7BitAbbrev;
for (const auto P : FuncName) NameVals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(bitc::VST_CODE_COMBINED_FNENTRY, NameVals, AbbrevToUse);
NameVals.clear();
}
}
Stream.ExitBlock();
}
static void WriteUseList(ValueEnumerator &VE, UseListOrder &&Order,
BitstreamWriter &Stream) {
assert(Order.Shuffle.size() >= 2 && "Shuffle too small");
@@ -2345,14 +2409,33 @@ static void WriteUseListBlock(const Function *F, ValueEnumerator &VE,
Stream.ExitBlock();
}
/// WriteFunction - Emit a function body to the module stream.
static void WriteFunction(const Function &F, ValueEnumerator &VE,
BitstreamWriter &Stream,
DenseMap<const Function *, uint64_t> &FunctionIndex) {
/// \brief Save information for the given function into the function index.
///
/// At a minimum this saves the bitcode index of the function record that
/// was just written. However, if we are emitting function summary information,
/// for example for ThinLTO, then a \a FunctionSummary object is created
/// to hold the provided summary information.
static void SaveFunctionInfo(
const Function &F,
DenseMap<const Function *, std::unique_ptr<FunctionInfo>> &FunctionIndex,
unsigned NumInsts, uint64_t BitcodeIndex, bool EmitFunctionSummary) {
std::unique_ptr<FunctionSummary> FuncSummary;
if (EmitFunctionSummary) {
FuncSummary = llvm::make_unique<FunctionSummary>(NumInsts);
FuncSummary->setLocalFunction(F.hasLocalLinkage());
}
FunctionIndex[&F] =
llvm::make_unique<FunctionInfo>(BitcodeIndex, std::move(FuncSummary));
}
/// Emit a function body to the module stream.
static void WriteFunction(
const Function &F, ValueEnumerator &VE, BitstreamWriter &Stream,
DenseMap<const Function *, std::unique_ptr<FunctionInfo>> &FunctionIndex,
bool EmitFunctionSummary) {
// Save the bitcode index of the start of this function block for recording
// in the VST.
uint64_t BitcodeIndex = Stream.GetCurrentBitNo();
FunctionIndex[&F] = BitcodeIndex;
Stream.EnterSubblock(bitc::FUNCTION_BLOCK_ID, 4);
VE.incorporateFunction(F);
@@ -2379,6 +2462,7 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE,
bool NeedsMetadataAttachment = F.hasMetadata();
DILocation *LastDL = nullptr;
unsigned NumInsts = 0;
// Finally, emit all the instructions, in order.
for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
@@ -2386,6 +2470,8 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE,
I != E; ++I) {
WriteInstruction(*I, InstID, VE, Stream, Vals);
if (!isa<DbgInfoIntrinsic>(I)) ++NumInsts;
if (!I->getType()->isVoidTy())
++InstID;
@@ -2422,6 +2508,9 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE,
WriteUseListBlock(&F, VE, Stream);
VE.purgeFunction();
Stream.ExitBlock();
SaveFunctionInfo(F, FunctionIndex, NumInsts, BitcodeIndex,
EmitFunctionSummary);
}
// Emit blockinfo, which defines the standard abbreviations etc.
@@ -2599,10 +2688,155 @@ static void WriteBlockInfo(const ValueEnumerator &VE, BitstreamWriter &Stream) {
Stream.ExitBlock();
}
/// Write the module path strings, currently only used when generating
/// a combined index file.
static void WriteModStrings(const FunctionInfoIndex *I,
BitstreamWriter &Stream) {
Stream.EnterSubblock(bitc::MODULE_STRTAB_BLOCK_ID, 3);
// TODO: See which abbrev sizes we actually need to emit
// 8-bit fixed-width MST_ENTRY strings.
BitCodeAbbrev *Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::MST_CODE_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
unsigned Abbrev8Bit = Stream.EmitAbbrev(Abbv);
// 7-bit fixed width MST_ENTRY strings.
Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::MST_CODE_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7));
unsigned Abbrev7Bit = Stream.EmitAbbrev(Abbv);
// 6-bit char6 MST_ENTRY strings.
Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::MST_CODE_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6));
unsigned Abbrev6Bit = Stream.EmitAbbrev(Abbv);
SmallVector<unsigned, 64> NameVals;
for (const StringMapEntry<uint64_t> &MPSE : I->modPathStringEntries()) {
StringEncoding Bits =
getStringEncoding(MPSE.getKey().data(), MPSE.getKey().size());
unsigned AbbrevToUse = Abbrev8Bit;
if (Bits == SE_Char6)
AbbrevToUse = Abbrev6Bit;
else if (Bits == SE_Fixed7)
AbbrevToUse = Abbrev7Bit;
NameVals.push_back(MPSE.getValue());
for (const auto P : MPSE.getKey()) NameVals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(bitc::MST_CODE_ENTRY, NameVals, AbbrevToUse);
NameVals.clear();
}
Stream.ExitBlock();
}
// Helper to emit a single function summary record.
static void WritePerModuleFunctionSummaryRecord(
SmallVector<unsigned, 64> &NameVals, FunctionSummary *FS, unsigned ValueID,
unsigned FSAbbrev, BitstreamWriter &Stream) {
assert(FS);
NameVals.push_back(ValueID);
NameVals.push_back(FS->isLocalFunction());
NameVals.push_back(FS->instCount());
// Emit the finished record.
Stream.EmitRecord(bitc::FS_CODE_PERMODULE_ENTRY, NameVals, FSAbbrev);
NameVals.clear();
}
/// Emit the per-module function summary section alongside the rest of
/// the module's bitcode.
static void WritePerModuleFunctionSummary(
DenseMap<const Function *, std::unique_ptr<FunctionInfo>> &FunctionIndex,
const Module *M, const ValueEnumerator &VE, BitstreamWriter &Stream) {
Stream.EnterSubblock(bitc::FUNCTION_SUMMARY_BLOCK_ID, 3);
// Abbrev for FS_CODE_PERMODULE_ENTRY.
BitCodeAbbrev *Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::FS_CODE_PERMODULE_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // islocal
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
unsigned FSAbbrev = Stream.EmitAbbrev(Abbv);
SmallVector<unsigned, 64> NameVals;
for (auto &I : FunctionIndex) {
// Skip anonymous functions. We will emit a function summary for
// any aliases below.
if (!I.first->hasName()) continue;
WritePerModuleFunctionSummaryRecord(
NameVals, I.second->functionSummary(),
VE.getValueID(M->getValueSymbolTable().lookup(I.first->getName())),
FSAbbrev, Stream);
}
for (const GlobalAlias &A : M->aliases()) {
if (!A.getBaseObject()) continue;
const Function *F = dyn_cast<Function>(A.getBaseObject());
if (!F || F->isDeclaration()) continue;
assert(FunctionIndex.count(F) == 1);
WritePerModuleFunctionSummaryRecord(
NameVals, FunctionIndex[F]->functionSummary(),
VE.getValueID(M->getValueSymbolTable().lookup(A.getName())), FSAbbrev,
Stream);
}
Stream.ExitBlock();
}
/// Emit the combined function summary section into the combined index
/// file.
static void WriteCombinedFunctionSummary(const FunctionInfoIndex *I,
BitstreamWriter &Stream) {
Stream.EnterSubblock(bitc::FUNCTION_SUMMARY_BLOCK_ID, 3);
// Abbrev for FS_CODE_COMBINED_ENTRY.
BitCodeAbbrev *Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::FS_CODE_COMBINED_ENTRY));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // modid
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
unsigned FSAbbrev = Stream.EmitAbbrev(Abbv);
SmallVector<unsigned, 64> NameVals;
for (const auto &FII : *I) {
for (auto &FI : FII.getValue()) {
FunctionSummary *FS = FI->functionSummary();
assert(FS);
NameVals.push_back(I->getModuleId(FS->modulePath()));
NameVals.push_back(FS->instCount());
// Record the starting offset of this summary entry for use
// in the VST entry. Add the current code size since the
// reader will invoke readRecord after the abbrev id read.
FI->setBitcodeIndex(Stream.GetCurrentBitNo() + Stream.GetAbbrevIDWidth());
// Emit the finished record.
Stream.EmitRecord(bitc::FS_CODE_COMBINED_ENTRY, NameVals, FSAbbrev);
NameVals.clear();
}
}
Stream.ExitBlock();
}
/// WriteModule - Emit the specified module to the bitstream.
static void WriteModule(const Module *M, BitstreamWriter &Stream,
bool ShouldPreserveUseListOrder,
uint64_t BitcodeStartBit) {
uint64_t BitcodeStartBit, bool EmitFunctionSummary) {
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
SmallVector<unsigned, 1> Vals;
@@ -2647,10 +2881,15 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream,
WriteOperandBundleTags(M, Stream);
// Emit function bodies.
DenseMap<const Function *, uint64_t> FunctionIndex;
DenseMap<const Function *, std::unique_ptr<FunctionInfo>> FunctionIndex;
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F)
if (!F->isDeclaration())
WriteFunction(*F, VE, Stream, FunctionIndex);
WriteFunction(*F, VE, Stream, FunctionIndex, EmitFunctionSummary);
// Need to write after the above call to WriteFunction which populates
// the summary information in the index.
if (EmitFunctionSummary)
WritePerModuleFunctionSummary(FunctionIndex, M, VE, Stream);
WriteValueSymbolTable(M->getValueSymbolTable(), VE, Stream,
VSTOffsetPlaceholder, BitcodeStartBit, &FunctionIndex);
@@ -2728,10 +2967,22 @@ static void EmitDarwinBCHeaderAndTrailer(SmallVectorImpl<char> &Buffer,
Buffer.push_back(0);
}
/// Helper to write the header common to all bitcode files.
static void WriteBitcodeHeader(BitstreamWriter &Stream) {
// Emit the file header.
Stream.Emit((unsigned)'B', 8);
Stream.Emit((unsigned)'C', 8);
Stream.Emit(0x0, 4);
Stream.Emit(0xC, 4);
Stream.Emit(0xE, 4);
Stream.Emit(0xD, 4);
}
/// WriteBitcodeToFile - Write the specified module to the specified output
/// stream.
void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
bool ShouldPreserveUseListOrder) {
bool ShouldPreserveUseListOrder,
bool EmitFunctionSummary) {
SmallVector<char, 0> Buffer;
Buffer.reserve(256*1024);
@@ -2751,15 +3002,11 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
uint64_t BitcodeStartBit = Stream.GetCurrentBitNo();
// Emit the file header.
Stream.Emit((unsigned)'B', 8);
Stream.Emit((unsigned)'C', 8);
Stream.Emit(0x0, 4);
Stream.Emit(0xC, 4);
Stream.Emit(0xE, 4);
Stream.Emit(0xD, 4);
WriteBitcodeHeader(Stream);
// Emit the module.
WriteModule(M, Stream, ShouldPreserveUseListOrder, BitcodeStartBit);
WriteModule(M, Stream, ShouldPreserveUseListOrder, BitcodeStartBit,
EmitFunctionSummary);
}
if (TT.isOSDarwin())
@@ -2768,3 +3015,38 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
// Write the generated bitstream to "Out".
Out.write((char*)&Buffer.front(), Buffer.size());
}
// Write the specified function summary index to the given raw output stream,
// where it will be written in a new bitcode block. This is used when
// writing the combined index file for ThinLTO.
void llvm::WriteFunctionSummaryToFile(const FunctionInfoIndex *Index,
raw_ostream &Out) {
SmallVector<char, 0> Buffer;
Buffer.reserve(256 * 1024);
BitstreamWriter Stream(Buffer);
// Emit the bitcode header.
WriteBitcodeHeader(Stream);
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);
// Write the module paths in the combined index.
WriteModStrings(Index, Stream);
// Write the function summary combined index records.
WriteCombinedFunctionSummary(Index, Stream);
// Need a special VST writer for the combined index (we don't have a
// real VST and real values when this is invoked).
WriteCombinedValueSymbolTable(Index, Stream);
Stream.ExitBlock();
Out.write((char *)&Buffer.front(), Buffer.size());
}