mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
Restore "[ThinLTO] Emit individual index files for distributed backends"
This restores commit r268627: Summary: When launching ThinLTO backends in a distributed build (currently supported in gold via the thinlto-index-only plugin option), emit an individual index file for each backend process as described here: http://lists.llvm.org/pipermail/llvm-dev/2016-April/098272.html ... Differential Revision: http://reviews.llvm.org/D19556 Address msan failures by avoiding std::prev on map.end(), the theory is that this is causing issues due to some known UB problems in __tree. llvm-svn: 269059
This commit is contained in:
parent
61778268f4
commit
4147326797
@ -97,8 +97,12 @@ namespace llvm {
|
|||||||
|
|
||||||
/// Write the specified module summary index to the given raw output stream,
|
/// Write the specified module summary index to the given raw output stream,
|
||||||
/// where it will be written in a new bitcode block. This is used when
|
/// where it will be written in a new bitcode block. This is used when
|
||||||
/// writing the combined index file for ThinLTO.
|
/// writing the combined index file for ThinLTO. When writing a subset of the
|
||||||
void WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out);
|
/// index for a distributed backend, provide the \p ModuleToSummariesForIndex
|
||||||
|
/// map.
|
||||||
|
void WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out,
|
||||||
|
std::map<std::string, GVSummaryMapTy>
|
||||||
|
*ModuleToSummariesForIndex = nullptr);
|
||||||
|
|
||||||
/// isBitcodeWrapper - Return true if the given bytes are the magic bytes
|
/// isBitcodeWrapper - Return true if the given bytes are the magic bytes
|
||||||
/// for an LLVM IR bitcode wrapper.
|
/// for an LLVM IR bitcode wrapper.
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "llvm-c/lto.h"
|
#include "llvm-c/lto.h"
|
||||||
#include "llvm/ADT/StringSet.h"
|
#include "llvm/ADT/StringSet.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
|
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||||
#include "llvm/Support/CodeGen.h"
|
#include "llvm/Support/CodeGen.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Target/TargetOptions.h"
|
#include "llvm/Target/TargetOptions.h"
|
||||||
@ -27,7 +28,6 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class StringRef;
|
class StringRef;
|
||||||
class ModuleSummaryIndex;
|
|
||||||
class LLVMContext;
|
class LLVMContext;
|
||||||
class TargetMachine;
|
class TargetMachine;
|
||||||
|
|
||||||
@ -207,6 +207,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void crossModuleImport(Module &Module, ModuleSummaryIndex &Index);
|
void crossModuleImport(Module &Module, ModuleSummaryIndex &Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the list of summaries needed for importing into module.
|
||||||
|
*/
|
||||||
|
static void gatherImportedSummariesForModule(
|
||||||
|
StringRef ModulePath, ModuleSummaryIndex &Index,
|
||||||
|
std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform internalization.
|
* Perform internalization.
|
||||||
*/
|
*/
|
||||||
|
@ -87,6 +87,22 @@ void ComputeCrossModuleImport(
|
|||||||
void ComputeCrossModuleImportForModule(
|
void ComputeCrossModuleImportForModule(
|
||||||
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
||||||
FunctionImporter::ImportMapTy &ImportList);
|
FunctionImporter::ImportMapTy &ImportList);
|
||||||
|
|
||||||
|
/// Compute the set of summaries needed for a ThinLTO backend compilation of
|
||||||
|
/// \p ModulePath.
|
||||||
|
//
|
||||||
|
/// This includes summaries from that module (in case any global summary based
|
||||||
|
/// optimizations were recorded) and from any definitions in other modules that
|
||||||
|
/// should be imported.
|
||||||
|
//
|
||||||
|
/// \p ModuleToSummariesForIndex will be populated with the needed summaries
|
||||||
|
/// from each required module path. Use a std::map instead of StringMap to get
|
||||||
|
/// stable order for bitcode emission.
|
||||||
|
void gatherImportedSummariesForModule(
|
||||||
|
StringRef ModulePath,
|
||||||
|
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
|
const StringMap<FunctionImporter::ImportMapTy> &ImportLists,
|
||||||
|
std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LLVM_FUNCTIONIMPORT_H
|
#endif // LLVM_FUNCTIONIMPORT_H
|
||||||
|
@ -263,6 +263,10 @@ class IndexBitcodeWriter : public BitcodeWriter {
|
|||||||
/// The combined index to write to bitcode.
|
/// The combined index to write to bitcode.
|
||||||
const ModuleSummaryIndex &Index;
|
const ModuleSummaryIndex &Index;
|
||||||
|
|
||||||
|
/// When writing a subset of the index for distributed backends, client
|
||||||
|
/// provides a map of modules to the corresponding GUIDs/summaries to write.
|
||||||
|
std::map<std::string, GVSummaryMapTy> *ModuleToSummariesForIndex;
|
||||||
|
|
||||||
/// Map that holds the correspondence between the GUID used in the combined
|
/// Map that holds the correspondence between the GUID used in the combined
|
||||||
/// index and a value id generated by this class to use in references.
|
/// index and a value id generated by this class to use in references.
|
||||||
std::map<GlobalValue::GUID, unsigned> GUIDToValueIdMap;
|
std::map<GlobalValue::GUID, unsigned> GUIDToValueIdMap;
|
||||||
@ -272,18 +276,148 @@ class IndexBitcodeWriter : public BitcodeWriter {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructs a IndexBitcodeWriter object for the given combined index,
|
/// Constructs a IndexBitcodeWriter object for the given combined index,
|
||||||
/// writing to the provided \p Buffer.
|
/// writing to the provided \p Buffer. When writing a subset of the index
|
||||||
|
/// for a distributed backend, provide a \p ModuleToSummariesForIndex map.
|
||||||
IndexBitcodeWriter(SmallVectorImpl<char> &Buffer,
|
IndexBitcodeWriter(SmallVectorImpl<char> &Buffer,
|
||||||
const ModuleSummaryIndex &Index)
|
const ModuleSummaryIndex &Index,
|
||||||
: BitcodeWriter(Buffer), Index(Index) {
|
std::map<std::string, GVSummaryMapTy>
|
||||||
// Assign unique value ids to all functions in the index for use
|
*ModuleToSummariesForIndex = nullptr)
|
||||||
|
: BitcodeWriter(Buffer), Index(Index),
|
||||||
|
ModuleToSummariesForIndex(ModuleToSummariesForIndex) {
|
||||||
|
// Assign unique value ids to all summaries to be written, for use
|
||||||
// in writing out the call graph edges. Save the mapping from GUID
|
// in writing out the call graph edges. Save the mapping from GUID
|
||||||
// to the new global value id to use when writing those edges, which
|
// to the new global value id to use when writing those edges, which
|
||||||
// are currently saved in the index in terms of GUID.
|
// are currently saved in the index in terms of GUID.
|
||||||
for (auto &II : Index)
|
for (const auto &I : *this)
|
||||||
GUIDToValueIdMap[II.first] = ++GlobalValueId;
|
GUIDToValueIdMap[I.first] = ++GlobalValueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The below iterator returns the GUID and associated summary.
|
||||||
|
typedef std::pair<GlobalValue::GUID, GlobalValueSummary *> GVInfo;
|
||||||
|
|
||||||
|
/// Iterator over the value GUID and summaries to be written to bitcode,
|
||||||
|
/// hides the details of whether they are being pulled from the entire
|
||||||
|
/// index or just those in a provided ModuleToSummariesForIndex map.
|
||||||
|
class iterator
|
||||||
|
: public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
|
||||||
|
GVInfo> {
|
||||||
|
/// Enables access to parent class.
|
||||||
|
const IndexBitcodeWriter &Writer;
|
||||||
|
|
||||||
|
// Iterators used when writing only those summaries in a provided
|
||||||
|
// ModuleToSummariesForIndex map:
|
||||||
|
|
||||||
|
/// Points to the last element in outer ModuleToSummariesForIndex map.
|
||||||
|
std::map<std::string, GVSummaryMapTy>::iterator ModuleSummariesBack;
|
||||||
|
/// Iterator on outer ModuleToSummariesForIndex map.
|
||||||
|
std::map<std::string, GVSummaryMapTy>::iterator ModuleSummariesIter;
|
||||||
|
/// Iterator on an inner global variable summary map.
|
||||||
|
GVSummaryMapTy::iterator ModuleGVSummariesIter;
|
||||||
|
|
||||||
|
// Iterators used when writing all summaries in the index:
|
||||||
|
|
||||||
|
/// Points to the last element in the Index outer GlobalValueMap.
|
||||||
|
const_gvsummary_iterator IndexSummariesBack;
|
||||||
|
/// Iterator on outer GlobalValueMap.
|
||||||
|
const_gvsummary_iterator IndexSummariesIter;
|
||||||
|
/// Iterator on an inner GlobalValueSummaryList.
|
||||||
|
GlobalValueSummaryList::const_iterator IndexGVSummariesIter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Construct iterator from parent \p Writer and indicate if we are
|
||||||
|
/// constructing the end iterator.
|
||||||
|
iterator(const IndexBitcodeWriter &Writer, bool IsAtEnd) : Writer(Writer) {
|
||||||
|
// Set up the appropriate set of iterators given whether we are writing
|
||||||
|
// the full index or just a subset.
|
||||||
|
// Can't setup the Back or inner iterators if the corresponding map
|
||||||
|
// is empty. This will be handled specially in operator== as well.
|
||||||
|
if (Writer.ModuleToSummariesForIndex &&
|
||||||
|
!Writer.ModuleToSummariesForIndex->empty()) {
|
||||||
|
ModuleSummariesIter = Writer.ModuleToSummariesForIndex->begin();
|
||||||
|
for (ModuleSummariesBack = Writer.ModuleToSummariesForIndex->begin();
|
||||||
|
std::next(ModuleSummariesBack) !=
|
||||||
|
Writer.ModuleToSummariesForIndex->end();
|
||||||
|
ModuleSummariesBack++)
|
||||||
|
;
|
||||||
|
ModuleGVSummariesIter = !IsAtEnd ? ModuleSummariesIter->second.begin()
|
||||||
|
: ModuleSummariesBack->second.end();
|
||||||
|
} else if (!Writer.ModuleToSummariesForIndex &&
|
||||||
|
Writer.Index.begin() != Writer.Index.end()) {
|
||||||
|
IndexSummariesIter = Writer.Index.begin();
|
||||||
|
for (IndexSummariesBack = Writer.Index.begin();
|
||||||
|
std::next(IndexSummariesBack) != Writer.Index.end();
|
||||||
|
IndexSummariesBack++)
|
||||||
|
;
|
||||||
|
IndexGVSummariesIter = !IsAtEnd ? IndexSummariesIter->second.begin()
|
||||||
|
: IndexSummariesBack->second.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increment the appropriate set of iterators.
|
||||||
|
iterator &operator++() {
|
||||||
|
// First the inner iterator is incremented, then if it is at the end
|
||||||
|
// and there are more outer iterations to go, the inner is reset to
|
||||||
|
// the start of the next inner list.
|
||||||
|
if (Writer.ModuleToSummariesForIndex) {
|
||||||
|
++ModuleGVSummariesIter;
|
||||||
|
if (ModuleGVSummariesIter == ModuleSummariesIter->second.end() &&
|
||||||
|
ModuleSummariesIter != ModuleSummariesBack) {
|
||||||
|
++ModuleSummariesIter;
|
||||||
|
ModuleGVSummariesIter = ModuleSummariesIter->second.begin();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++IndexGVSummariesIter;
|
||||||
|
if (IndexGVSummariesIter == IndexSummariesIter->second.end() &&
|
||||||
|
IndexSummariesIter != IndexSummariesBack) {
|
||||||
|
++IndexSummariesIter;
|
||||||
|
IndexGVSummariesIter = IndexSummariesIter->second.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the <GUID,GlobalValueSummary*> pair corresponding to the current
|
||||||
|
/// outer and inner iterator positions.
|
||||||
|
GVInfo operator*() {
|
||||||
|
if (Writer.ModuleToSummariesForIndex)
|
||||||
|
return std::make_pair(ModuleGVSummariesIter->first,
|
||||||
|
ModuleGVSummariesIter->second);
|
||||||
|
return std::make_pair(IndexSummariesIter->first,
|
||||||
|
IndexGVSummariesIter->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the iterators are equal, with special handling for empty
|
||||||
|
/// indexes.
|
||||||
|
bool operator==(const iterator &RHS) const {
|
||||||
|
if (Writer.ModuleToSummariesForIndex) {
|
||||||
|
// First ensure that both are writing the same subset.
|
||||||
|
if (Writer.ModuleToSummariesForIndex !=
|
||||||
|
RHS.Writer.ModuleToSummariesForIndex)
|
||||||
|
return false;
|
||||||
|
// Already determined above that maps are the same, so if one is
|
||||||
|
// empty, they both are.
|
||||||
|
if (Writer.ModuleToSummariesForIndex->empty())
|
||||||
|
return true;
|
||||||
|
return ModuleGVSummariesIter == RHS.ModuleGVSummariesIter;
|
||||||
|
}
|
||||||
|
// First ensure RHS also writing the full index, and that both are
|
||||||
|
// writing the same full index.
|
||||||
|
if (RHS.Writer.ModuleToSummariesForIndex ||
|
||||||
|
&Writer.Index != &RHS.Writer.Index)
|
||||||
|
return false;
|
||||||
|
// Already determined above that maps are the same, so if one is
|
||||||
|
// empty, they both are.
|
||||||
|
if (Writer.Index.begin() == Writer.Index.end())
|
||||||
|
return true;
|
||||||
|
return IndexGVSummariesIter == RHS.IndexGVSummariesIter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Obtain the start iterator over the summaries to be written.
|
||||||
|
iterator begin() { return iterator(*this, /*IsAtEnd=*/false); }
|
||||||
|
/// Obtain the end iterator over the summaries to be written.
|
||||||
|
iterator end() { return iterator(*this, /*IsAtEnd=*/true); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Main entry point for writing a combined index to bitcode, invoked by
|
/// Main entry point for writing a combined index to bitcode, invoked by
|
||||||
/// BitcodeWriter::write() after it writes the header.
|
/// BitcodeWriter::write() after it writes the header.
|
||||||
@ -294,6 +428,14 @@ private:
|
|||||||
void writeCombinedValueSymbolTable();
|
void writeCombinedValueSymbolTable();
|
||||||
void writeCombinedGlobalValueSummary();
|
void writeCombinedGlobalValueSummary();
|
||||||
|
|
||||||
|
/// Indicates whether the provided \p ModulePath should be written into
|
||||||
|
/// the module string table, e.g. if full index written or if it is in
|
||||||
|
/// the provided subset.
|
||||||
|
bool doIncludeModule(StringRef ModulePath) {
|
||||||
|
return !ModuleToSummariesForIndex ||
|
||||||
|
ModuleToSummariesForIndex->count(ModulePath);
|
||||||
|
}
|
||||||
|
|
||||||
bool hasValueId(GlobalValue::GUID ValGUID) {
|
bool hasValueId(GlobalValue::GUID ValGUID) {
|
||||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||||
return VMI != GUIDToValueIdMap.end();
|
return VMI != GUIDToValueIdMap.end();
|
||||||
@ -2964,6 +3106,8 @@ void IndexBitcodeWriter::writeModStrings() {
|
|||||||
|
|
||||||
SmallVector<unsigned, 64> Vals;
|
SmallVector<unsigned, 64> Vals;
|
||||||
for (const auto &MPSE : Index.modulePaths()) {
|
for (const auto &MPSE : Index.modulePaths()) {
|
||||||
|
if (!doIncludeModule(MPSE.getKey()))
|
||||||
|
continue;
|
||||||
StringEncoding Bits =
|
StringEncoding Bits =
|
||||||
getStringEncoding(MPSE.getKey().data(), MPSE.getKey().size());
|
getStringEncoding(MPSE.getKey().data(), MPSE.getKey().size());
|
||||||
unsigned AbbrevToUse = Abbrev8Bit;
|
unsigned AbbrevToUse = Abbrev8Bit;
|
||||||
@ -3217,78 +3361,75 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||||||
NameVals.clear();
|
NameVals.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &GSI : Index) {
|
for (const auto &I : *this) {
|
||||||
for (auto &SI : GSI.second) {
|
GlobalValueSummary *S = I.second;
|
||||||
GlobalValueSummary *S = SI.get();
|
assert(S);
|
||||||
assert(S);
|
|
||||||
|
|
||||||
assert(hasValueId(GSI.first));
|
assert(hasValueId(I.first));
|
||||||
unsigned ValueId = getValueId(GSI.first);
|
unsigned ValueId = getValueId(I.first);
|
||||||
SummaryToValueIdMap[S] = ValueId;
|
SummaryToValueIdMap[S] = ValueId;
|
||||||
|
|
||||||
if (auto *AS = dyn_cast<AliasSummary>(S)) {
|
if (auto *AS = dyn_cast<AliasSummary>(S)) {
|
||||||
// Will process aliases as a post-pass because the reader wants all
|
// Will process aliases as a post-pass because the reader wants all
|
||||||
// global to be loaded first.
|
// global to be loaded first.
|
||||||
Aliases.push_back(AS);
|
Aliases.push_back(AS);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto *VS = dyn_cast<GlobalVarSummary>(S)) {
|
if (auto *VS = dyn_cast<GlobalVarSummary>(S)) {
|
||||||
NameVals.push_back(ValueId);
|
|
||||||
NameVals.push_back(Index.getModuleId(VS->modulePath()));
|
|
||||||
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
|
|
||||||
for (auto &RI : VS->refs()) {
|
|
||||||
NameVals.push_back(getValueId(RI.getGUID()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the finished record.
|
|
||||||
Stream.EmitRecord(bitc::FS_COMBINED_GLOBALVAR_INIT_REFS, NameVals,
|
|
||||||
FSModRefsAbbrev);
|
|
||||||
NameVals.clear();
|
|
||||||
MaybeEmitOriginalName(*S);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *FS = cast<FunctionSummary>(S);
|
|
||||||
NameVals.push_back(ValueId);
|
NameVals.push_back(ValueId);
|
||||||
NameVals.push_back(Index.getModuleId(FS->modulePath()));
|
NameVals.push_back(Index.getModuleId(VS->modulePath()));
|
||||||
NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
|
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
|
||||||
NameVals.push_back(FS->instCount());
|
for (auto &RI : VS->refs()) {
|
||||||
NameVals.push_back(FS->refs().size());
|
|
||||||
|
|
||||||
for (auto &RI : FS->refs()) {
|
|
||||||
NameVals.push_back(getValueId(RI.getGUID()));
|
NameVals.push_back(getValueId(RI.getGUID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasProfileData = false;
|
|
||||||
for (auto &EI : FS->calls()) {
|
|
||||||
HasProfileData |= EI.second.ProfileCount != 0;
|
|
||||||
if (HasProfileData)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &EI : FS->calls()) {
|
|
||||||
// If this GUID doesn't have a value id, it doesn't have a function
|
|
||||||
// summary and we don't need to record any calls to it.
|
|
||||||
if (!hasValueId(EI.first.getGUID()))
|
|
||||||
continue;
|
|
||||||
NameVals.push_back(getValueId(EI.first.getGUID()));
|
|
||||||
assert(EI.second.CallsiteCount > 0 && "Expected at least one callsite");
|
|
||||||
NameVals.push_back(EI.second.CallsiteCount);
|
|
||||||
if (HasProfileData)
|
|
||||||
NameVals.push_back(EI.second.ProfileCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned FSAbbrev =
|
|
||||||
(HasProfileData ? FSCallsProfileAbbrev : FSCallsAbbrev);
|
|
||||||
unsigned Code =
|
|
||||||
(HasProfileData ? bitc::FS_COMBINED_PROFILE : bitc::FS_COMBINED);
|
|
||||||
|
|
||||||
// Emit the finished record.
|
// Emit the finished record.
|
||||||
Stream.EmitRecord(Code, NameVals, FSAbbrev);
|
Stream.EmitRecord(bitc::FS_COMBINED_GLOBALVAR_INIT_REFS, NameVals,
|
||||||
|
FSModRefsAbbrev);
|
||||||
NameVals.clear();
|
NameVals.clear();
|
||||||
MaybeEmitOriginalName(*S);
|
MaybeEmitOriginalName(*S);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto *FS = cast<FunctionSummary>(S);
|
||||||
|
NameVals.push_back(ValueId);
|
||||||
|
NameVals.push_back(Index.getModuleId(FS->modulePath()));
|
||||||
|
NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
|
||||||
|
NameVals.push_back(FS->instCount());
|
||||||
|
NameVals.push_back(FS->refs().size());
|
||||||
|
|
||||||
|
for (auto &RI : FS->refs()) {
|
||||||
|
NameVals.push_back(getValueId(RI.getGUID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasProfileData = false;
|
||||||
|
for (auto &EI : FS->calls()) {
|
||||||
|
HasProfileData |= EI.second.ProfileCount != 0;
|
||||||
|
if (HasProfileData)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &EI : FS->calls()) {
|
||||||
|
// If this GUID doesn't have a value id, it doesn't have a function
|
||||||
|
// summary and we don't need to record any calls to it.
|
||||||
|
if (!hasValueId(EI.first.getGUID()))
|
||||||
|
continue;
|
||||||
|
NameVals.push_back(getValueId(EI.first.getGUID()));
|
||||||
|
assert(EI.second.CallsiteCount > 0 && "Expected at least one callsite");
|
||||||
|
NameVals.push_back(EI.second.CallsiteCount);
|
||||||
|
if (HasProfileData)
|
||||||
|
NameVals.push_back(EI.second.ProfileCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned FSAbbrev = (HasProfileData ? FSCallsProfileAbbrev : FSCallsAbbrev);
|
||||||
|
unsigned Code =
|
||||||
|
(HasProfileData ? bitc::FS_COMBINED_PROFILE : bitc::FS_COMBINED);
|
||||||
|
|
||||||
|
// Emit the finished record.
|
||||||
|
Stream.EmitRecord(Code, NameVals, FSAbbrev);
|
||||||
|
NameVals.clear();
|
||||||
|
MaybeEmitOriginalName(*S);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto *AS : Aliases) {
|
for (auto *AS : Aliases) {
|
||||||
@ -3562,12 +3703,15 @@ void IndexBitcodeWriter::writeIndex() {
|
|||||||
|
|
||||||
// Write the specified module summary index to the given raw output stream,
|
// Write the specified module summary index to the given raw output stream,
|
||||||
// where it will be written in a new bitcode block. This is used when
|
// where it will be written in a new bitcode block. This is used when
|
||||||
// writing the combined index file for ThinLTO.
|
// writing the combined index file for ThinLTO. When writing a subset of the
|
||||||
void llvm::WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out) {
|
// index for a distributed backend, provide a \p ModuleToSummariesForIndex map.
|
||||||
|
void llvm::WriteIndexToFile(
|
||||||
|
const ModuleSummaryIndex &Index, raw_ostream &Out,
|
||||||
|
std::map<std::string, GVSummaryMapTy> *ModuleToSummariesForIndex) {
|
||||||
SmallVector<char, 0> Buffer;
|
SmallVector<char, 0> Buffer;
|
||||||
Buffer.reserve(256 * 1024);
|
Buffer.reserve(256 * 1024);
|
||||||
|
|
||||||
IndexBitcodeWriter IndexWriter(Buffer, Index);
|
IndexBitcodeWriter IndexWriter(Buffer, Index, ModuleToSummariesForIndex);
|
||||||
IndexWriter.write();
|
IndexWriter.write();
|
||||||
|
|
||||||
Out.write((char *)&Buffer.front(), Buffer.size());
|
Out.write((char *)&Buffer.front(), Buffer.size());
|
||||||
|
@ -719,6 +719,29 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
|
|||||||
crossImportIntoModule(TheModule, Index, ModuleMap, ImportList);
|
crossImportIntoModule(TheModule, Index, ModuleMap, ImportList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the list of summaries needed for importing into module.
|
||||||
|
*/
|
||||||
|
void ThinLTOCodeGenerator::gatherImportedSummariesForModule(
|
||||||
|
StringRef ModulePath, ModuleSummaryIndex &Index,
|
||||||
|
std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex) {
|
||||||
|
auto ModuleCount = Index.modulePaths().size();
|
||||||
|
|
||||||
|
// Collect for each module the list of function it defines (GUID -> Summary).
|
||||||
|
StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount);
|
||||||
|
Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
|
||||||
|
|
||||||
|
// Generate import/export list
|
||||||
|
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
|
||||||
|
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
|
||||||
|
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||||
|
ExportLists);
|
||||||
|
|
||||||
|
llvm::gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
|
||||||
|
ImportLists,
|
||||||
|
ModuleToSummariesForIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform internalization.
|
* Perform internalization.
|
||||||
*/
|
*/
|
||||||
|
@ -418,6 +418,33 @@ void llvm::ComputeCrossModuleImportForModule(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the set of summaries needed for a ThinLTO backend compilation of
|
||||||
|
/// \p ModulePath.
|
||||||
|
void llvm::gatherImportedSummariesForModule(
|
||||||
|
StringRef ModulePath,
|
||||||
|
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
|
const StringMap<FunctionImporter::ImportMapTy> &ImportLists,
|
||||||
|
std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex) {
|
||||||
|
// Include all summaries from the importing module.
|
||||||
|
ModuleToSummariesForIndex[ModulePath] =
|
||||||
|
ModuleToDefinedGVSummaries.lookup(ModulePath);
|
||||||
|
auto ModuleImports = ImportLists.find(ModulePath);
|
||||||
|
if (ModuleImports != ImportLists.end()) {
|
||||||
|
// Include summaries for imports.
|
||||||
|
for (auto &ILI : ModuleImports->second) {
|
||||||
|
auto &SummariesForIndex = ModuleToSummariesForIndex[ILI.first()];
|
||||||
|
const auto &DefinedGVSummaries =
|
||||||
|
ModuleToDefinedGVSummaries.lookup(ILI.first());
|
||||||
|
for (auto &GI : ILI.second) {
|
||||||
|
const auto &DS = DefinedGVSummaries.find(GI.first);
|
||||||
|
assert(DS != DefinedGVSummaries.end() &&
|
||||||
|
"Expected a defined summary for imported global value");
|
||||||
|
SummariesForIndex[GI.first] = DS->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Automatically import functions in Module \p DestModule based on the summaries
|
// Automatically import functions in Module \p DestModule based on the summaries
|
||||||
// index.
|
// index.
|
||||||
//
|
//
|
||||||
|
4
test/ThinLTO/X86/Inputs/distributed_indexes.ll
Normal file
4
test/ThinLTO/X86/Inputs/distributed_indexes.ll
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
define void @g() {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
47
test/ThinLTO/X86/distributed_indexes.ll
Normal file
47
test/ThinLTO/X86/distributed_indexes.ll
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
; RUN: opt -module-summary %s -o %t1.bc
|
||||||
|
; RUN: opt -module-summary %p/Inputs/distributed_indexes.ll -o %t2.bc
|
||||||
|
; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc
|
||||||
|
; RUN: llvm-lto -thinlto-action=distributedindexes -thinlto-index %t.index.bc %t1.bc %t2.bc
|
||||||
|
; RUN: llvm-bcanalyzer -dump %t1.bc.thinlto.bc | FileCheck %s --check-prefix=BACKEND1
|
||||||
|
; RUN: llvm-bcanalyzer -dump %t2.bc.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
|
||||||
|
|
||||||
|
; The backend index for this module contains summaries from itself and
|
||||||
|
; Inputs/distributed_indexes.ll, as it imports from the latter.
|
||||||
|
; BACKEND1: <MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}distributed_indexes.ll.tmp{{.*}}.bc'
|
||||||
|
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}distributed_indexes.ll.tmp{{.*}}.bc'
|
||||||
|
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||||
|
; BACKEND1-NEXT: <VERSION
|
||||||
|
; 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.
|
||||||
|
; BACKEND2: <MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}distributed_indexes.ll.tmp2.bc'
|
||||||
|
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||||
|
; BACKEND2-NEXT: <VERSION
|
||||||
|
; 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(...)
|
||||||
|
|
||||||
|
define void @f() {
|
||||||
|
entry:
|
||||||
|
call void (...) @g()
|
||||||
|
ret void
|
||||||
|
}
|
@ -21,7 +21,8 @@
|
|||||||
; RUN: --plugin-opt=thinlto \
|
; RUN: --plugin-opt=thinlto \
|
||||||
; RUN: --plugin-opt=thinlto-index-only \
|
; RUN: --plugin-opt=thinlto-index-only \
|
||||||
; RUN: -shared %t.o %t2.o -o %t3
|
; RUN: -shared %t.o %t2.o -o %t3
|
||||||
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
|
; RUN: llvm-bcanalyzer -dump %t.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND1
|
||||||
|
; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
|
||||||
; RUN: not test -e %t3
|
; RUN: not test -e %t3
|
||||||
|
|
||||||
; Ensure gold generates an index as well as a binary by default in ThinLTO mode.
|
; Ensure gold generates an index as well as a binary by default in ThinLTO mode.
|
||||||
@ -53,6 +54,39 @@
|
|||||||
; NM: T f
|
; NM: T f
|
||||||
; NM2: T {{f|g}}
|
; NM2: T {{f|g}}
|
||||||
|
|
||||||
|
; The backend index for this module contains summaries from itself and
|
||||||
|
; Inputs/thinlto.ll, as it imports from the latter.
|
||||||
|
; BACKEND1: <MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
||||||
|
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
||||||
|
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||||
|
; BACKEND1-NEXT: <VERSION
|
||||||
|
; 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.
|
||||||
|
; BACKEND2: <MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp2.o'
|
||||||
|
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
|
||||||
|
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||||
|
; BACKEND2-NEXT: <VERSION
|
||||||
|
; 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: <MODULE_STRTAB_BLOCK
|
||||||
; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
||||||
; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
; COMBINED-NEXT: <ENTRY {{.*}} record string = '{{.*}}/test/tools/gold/X86/Output/thinlto.ll.tmp{{.*}}.o'
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Support/thread.h"
|
#include "llvm/Support/thread.h"
|
||||||
#include "llvm/Transforms/IPO.h"
|
#include "llvm/Transforms/IPO.h"
|
||||||
|
#include "llvm/Transforms/IPO/FunctionImport.h"
|
||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
||||||
#include "llvm/Transforms/Utils/GlobalStatus.h"
|
#include "llvm/Transforms/Utils/GlobalStatus.h"
|
||||||
@ -179,7 +180,8 @@ namespace options {
|
|||||||
static bool thinlto = false;
|
static bool thinlto = false;
|
||||||
// If false, all ThinLTO backend compilations through code gen are performed
|
// If false, all ThinLTO backend compilations through code gen are performed
|
||||||
// using multiple threads in the gold-plugin, before handing control back to
|
// using multiple threads in the gold-plugin, before handing control back to
|
||||||
// gold. If true, exit after creating the combined index, the assuming is
|
// gold. If true, write individual backend index files which reflect
|
||||||
|
// the import decisions, and exit afterwards. The assumption is
|
||||||
// that the build system will launch the backend processes.
|
// that the build system will launch the backend processes.
|
||||||
static bool thinlto_index_only = false;
|
static bool thinlto_index_only = false;
|
||||||
// Additional options to pass into the code generator.
|
// Additional options to pass into the code generator.
|
||||||
@ -1190,6 +1192,79 @@ static void thinLTOBackends(raw_fd_ostream *ApiFile,
|
|||||||
Task.cleanup();
|
Task.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform ThinLTO link, which creates the combined index file.
|
||||||
|
/// Also, either launch backend threads or (under thinlto-index-only)
|
||||||
|
/// emit individual index files for distributed backends and exit.
|
||||||
|
static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
|
||||||
|
ModuleSummaryIndex CombinedIndex;
|
||||||
|
uint64_t NextModuleId = 0;
|
||||||
|
for (claimed_file &F : Modules) {
|
||||||
|
PluginInputFile InputFile(F.handle);
|
||||||
|
|
||||||
|
std::unique_ptr<ModuleSummaryIndex> Index =
|
||||||
|
getModuleSummaryIndexForFile(F, InputFile.file());
|
||||||
|
|
||||||
|
// Skip files without a module summary.
|
||||||
|
if (Index)
|
||||||
|
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options::thinlto_index_only) {
|
||||||
|
// Collect for each module the list of function it defines (GUID ->
|
||||||
|
// Summary).
|
||||||
|
StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
|
||||||
|
ModuleToDefinedGVSummaries(NextModuleId);
|
||||||
|
CombinedIndex.collectDefinedGVSummariesPerModule(
|
||||||
|
ModuleToDefinedGVSummaries);
|
||||||
|
|
||||||
|
// FIXME: We want to do this for the case where the threads are launched
|
||||||
|
// from gold as well, in which case this will be moved out of the
|
||||||
|
// thinlto_index_only handling, and the function importer will be invoked
|
||||||
|
// directly using the Lists.
|
||||||
|
StringMap<FunctionImporter::ImportMapTy> ImportLists(NextModuleId);
|
||||||
|
StringMap<FunctionImporter::ExportSetTy> ExportLists(NextModuleId);
|
||||||
|
ComputeCrossModuleImport(CombinedIndex, ModuleToDefinedGVSummaries,
|
||||||
|
ImportLists, ExportLists);
|
||||||
|
|
||||||
|
// For each input bitcode file, generate an individual index that
|
||||||
|
// contains summaries only for its own global values, and for any that
|
||||||
|
// should be imported.
|
||||||
|
for (claimed_file &F : Modules) {
|
||||||
|
PluginInputFile InputFile(F.handle);
|
||||||
|
std::error_code EC;
|
||||||
|
raw_fd_ostream OS((Twine(InputFile.file().name) + ".thinlto.bc").str(),
|
||||||
|
EC, sys::fs::OpenFlags::F_None);
|
||||||
|
if (EC)
|
||||||
|
message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
|
||||||
|
InputFile.file().name, EC.message().c_str());
|
||||||
|
// Build a map of module to the GUIDs and summary objects that should
|
||||||
|
// be written to its index.
|
||||||
|
std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
|
||||||
|
gatherImportedSummariesForModule(InputFile.file().name,
|
||||||
|
ModuleToDefinedGVSummaries, ImportLists,
|
||||||
|
ModuleToSummariesForIndex);
|
||||||
|
WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_hook();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create OS in nested scope so that it will be closed on destruction.
|
||||||
|
{
|
||||||
|
std::error_code EC;
|
||||||
|
raw_fd_ostream OS(output_name + ".thinlto.bc", EC,
|
||||||
|
sys::fs::OpenFlags::F_None);
|
||||||
|
if (EC)
|
||||||
|
message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
|
||||||
|
output_name.data(), EC.message().c_str());
|
||||||
|
WriteIndexToFile(CombinedIndex, OS);
|
||||||
|
}
|
||||||
|
|
||||||
|
thinLTOBackends(ApiFile, CombinedIndex);
|
||||||
|
return LDPS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// gold informs us that all symbols have been read. At this point, we use
|
/// gold informs us that all symbols have been read. At this point, we use
|
||||||
/// get_symbols to see if any of our definitions have been overridden by a
|
/// get_symbols to see if any of our definitions have been overridden by a
|
||||||
/// native object file. Then, perform optimization and codegen.
|
/// native object file. Then, perform optimization and codegen.
|
||||||
@ -1200,40 +1275,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
|
|||||||
if (unsigned NumOpts = options::extra.size())
|
if (unsigned NumOpts = options::extra.size())
|
||||||
cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
|
cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
|
||||||
|
|
||||||
// If we are doing ThinLTO compilation, simply build the combined
|
if (options::thinlto)
|
||||||
// module index/summary and emit it. We don't need to parse the modules
|
return thinLTOLink(ApiFile);
|
||||||
// and link them in this case.
|
|
||||||
if (options::thinlto) {
|
|
||||||
ModuleSummaryIndex CombinedIndex;
|
|
||||||
uint64_t NextModuleId = 0;
|
|
||||||
for (claimed_file &F : Modules) {
|
|
||||||
PluginInputFile InputFile(F.handle);
|
|
||||||
|
|
||||||
std::unique_ptr<ModuleSummaryIndex> Index =
|
|
||||||
getModuleSummaryIndexForFile(F, InputFile.file());
|
|
||||||
|
|
||||||
// Skip files without a module summary.
|
|
||||||
if (Index)
|
|
||||||
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::error_code EC;
|
|
||||||
raw_fd_ostream OS(output_name + ".thinlto.bc", EC,
|
|
||||||
sys::fs::OpenFlags::F_None);
|
|
||||||
if (EC)
|
|
||||||
message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
|
|
||||||
output_name.data(), EC.message().c_str());
|
|
||||||
WriteIndexToFile(CombinedIndex, OS);
|
|
||||||
OS.close();
|
|
||||||
|
|
||||||
if (options::thinlto_index_only) {
|
|
||||||
cleanup_hook();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
thinLTOBackends(ApiFile, CombinedIndex);
|
|
||||||
return LDPS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVMContext Context;
|
LLVMContext Context;
|
||||||
Context.setDiscardValueNames(options::TheOutputType !=
|
Context.setDiscardValueNames(options::TheOutputType !=
|
||||||
|
@ -66,6 +66,7 @@ static cl::opt<bool>
|
|||||||
|
|
||||||
enum ThinLTOModes {
|
enum ThinLTOModes {
|
||||||
THINLINK,
|
THINLINK,
|
||||||
|
THINDISTRIBUTE,
|
||||||
THINPROMOTE,
|
THINPROMOTE,
|
||||||
THINIMPORT,
|
THINIMPORT,
|
||||||
THININTERNALIZE,
|
THININTERNALIZE,
|
||||||
@ -80,6 +81,8 @@ cl::opt<ThinLTOModes> ThinLTOMode(
|
|||||||
clEnumValN(
|
clEnumValN(
|
||||||
THINLINK, "thinlink",
|
THINLINK, "thinlink",
|
||||||
"ThinLink: produces the index by linking only the summaries."),
|
"ThinLink: produces the index by linking only the summaries."),
|
||||||
|
clEnumValN(THINDISTRIBUTE, "distributedindexes",
|
||||||
|
"Produces individual indexes for distributed backends."),
|
||||||
clEnumValN(THINPROMOTE, "promote",
|
clEnumValN(THINPROMOTE, "promote",
|
||||||
"Perform pre-import promotion (requires -thinlto-index)."),
|
"Perform pre-import promotion (requires -thinlto-index)."),
|
||||||
clEnumValN(THINIMPORT, "import", "Perform both promotion and "
|
clEnumValN(THINIMPORT, "import", "Perform both promotion and "
|
||||||
@ -354,6 +357,8 @@ public:
|
|||||||
switch (ThinLTOMode) {
|
switch (ThinLTOMode) {
|
||||||
case THINLINK:
|
case THINLINK:
|
||||||
return thinLink();
|
return thinLink();
|
||||||
|
case THINDISTRIBUTE:
|
||||||
|
return distributedIndexes();
|
||||||
case THINPROMOTE:
|
case THINPROMOTE:
|
||||||
return promote();
|
return promote();
|
||||||
case THINIMPORT:
|
case THINIMPORT:
|
||||||
@ -396,6 +401,36 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the combined index from disk, then compute and generate
|
||||||
|
/// individual index files suitable for ThinLTO distributed backend builds
|
||||||
|
/// on the files mentioned on the command line (these must match the index
|
||||||
|
/// content).
|
||||||
|
void distributedIndexes() {
|
||||||
|
if (InputFilenames.size() != 1 && !OutputFilename.empty())
|
||||||
|
report_fatal_error("Can't handle a single output filename and multiple "
|
||||||
|
"input files, do not provide an output filename and "
|
||||||
|
"the output files will be suffixed from the input "
|
||||||
|
"ones.");
|
||||||
|
|
||||||
|
auto Index = loadCombinedIndex();
|
||||||
|
for (auto &Filename : InputFilenames) {
|
||||||
|
// Build a map of module to the GUIDs and summary objects that should
|
||||||
|
// be written to its index.
|
||||||
|
std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
|
||||||
|
ThinLTOCodeGenerator::gatherImportedSummariesForModule(
|
||||||
|
Filename, *Index, ModuleToSummariesForIndex);
|
||||||
|
|
||||||
|
std::string OutputName = OutputFilename;
|
||||||
|
if (OutputName.empty()) {
|
||||||
|
OutputName = Filename + ".thinlto.bc";
|
||||||
|
}
|
||||||
|
std::error_code EC;
|
||||||
|
raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None);
|
||||||
|
error(EC, "error opening the file '" + OutputName + "'");
|
||||||
|
WriteIndexToFile(*Index, OS, &ModuleToSummariesForIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Load the combined index from disk, then load every file referenced by
|
/// Load the combined index from disk, then load every file referenced by
|
||||||
/// the index and add them to the generator, finally perform the promotion
|
/// the index and add them to the generator, finally perform the promotion
|
||||||
/// on the files mentioned on the command line (these must match the index
|
/// on the files mentioned on the command line (these must match the index
|
||||||
|
Loading…
Reference in New Issue
Block a user