Skip to content

Commit

Permalink
[ThinLTO] Enable importing of aliases as copy of aliasee
Browse files Browse the repository at this point in the history
Summary:
This implements a missing feature to allow importing of aliases, which
was previously disabled because alias cannot be available_externally.
We instead import an alias as a copy of its aliasee.

Some additional work was required in the IndexBitcodeWriter for the
distributed build case, to ensure that the aliasee has a value id
in the distributed index file (i.e. even when it is not being
imported directly).

This is a performance win in codes that have many aliases, e.g. C++
applications that have many constructor and destructor aliases.

Reviewers: pcc

Subscribers: mehdi_amini, inglorion, eraman, llvm-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@320895 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
teresajohnson committed Dec 16, 2017
1 parent 2d82935 commit 2140d92
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 81 deletions.
18 changes: 17 additions & 1 deletion include/llvm/IR/ModuleSummaryIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ class GlobalValueSummary {
/// If this is an alias summary, returns the summary of the aliased object (a
/// global variable or function), otherwise returns itself.
GlobalValueSummary *getBaseObject();
const GlobalValueSummary *getBaseObject() const;

friend class ModuleSummaryIndex;
friend void computeDeadSymbols(class ModuleSummaryIndex &,
Expand All @@ -255,17 +256,22 @@ class GlobalValueSummary {
/// \brief Alias summary information.
class AliasSummary : public GlobalValueSummary {
GlobalValueSummary *AliaseeSummary;
// AliaseeGUID is only set and accessed when we are building a combined index
// via the BitcodeReader.
GlobalValue::GUID AliaseeGUID;

public:
AliasSummary(GVFlags Flags)
: GlobalValueSummary(AliasKind, Flags, ArrayRef<ValueInfo>{}) {}
: GlobalValueSummary(AliasKind, Flags, ArrayRef<ValueInfo>{}),
AliaseeSummary(nullptr), AliaseeGUID(0) {}

/// Check if this is an alias summary.
static bool classof(const GlobalValueSummary *GVS) {
return GVS->getSummaryKind() == AliasKind;
}

void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; }
void setAliaseeGUID(GlobalValue::GUID GUID) { AliaseeGUID = GUID; }

const GlobalValueSummary &getAliasee() const {
assert(AliaseeSummary && "Unexpected missing aliasee summary");
Expand All @@ -276,8 +282,18 @@ class AliasSummary : public GlobalValueSummary {
return const_cast<GlobalValueSummary &>(
static_cast<const AliasSummary *>(this)->getAliasee());
}
const GlobalValue::GUID &getAliaseeGUID() const {
assert(AliaseeGUID && "Unexpected missing aliasee GUID");
return AliaseeGUID;
}
};

const inline GlobalValueSummary *GlobalValueSummary::getBaseObject() const {
if (auto *AS = dyn_cast<AliasSummary>(this))
return &AS->getAliasee();
return this;
}

inline GlobalValueSummary *GlobalValueSummary::getBaseObject() {
if (auto *AS = dyn_cast<AliasSummary>(this))
return &AS->getAliasee();
Expand Down
4 changes: 4 additions & 0 deletions include/llvm/IR/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ class Value {
return UseList == nullptr;
}

bool materialized_use_empty() const {
return UseList == nullptr;
}

using use_iterator = use_iterator_impl<Use>;
using const_use_iterator = use_iterator_impl<const Use>;

Expand Down
9 changes: 9 additions & 0 deletions include/llvm/Transforms/IPO/FunctionImport.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ void ComputeCrossModuleImportForModule(
StringRef ModulePath, const ModuleSummaryIndex &Index,
FunctionImporter::ImportMapTy &ImportList);

/// Mark all external summaries in \p Index for import into the given module.
/// Used for distributed builds using a distributed index.
///
/// \p ImportList will be populated with a map that can be passed to
/// FunctionImporter::importFunctions() above (see description there).
void ComputeCrossModuleImportForModuleFromIndex(
StringRef ModulePath, const ModuleSummaryIndex &Index,
FunctionImporter::ImportMapTy &ImportList);

/// Compute all the symbols that are "dead": i.e these that can't be reached
/// in the graph from any of the given symbols listed in
/// \p GUIDPreservedSymbols.
Expand Down
4 changes: 2 additions & 2 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5202,6 +5202,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
if (!AliaseeInModule)
return error("Alias expects aliasee summary to be parsed");
AS->setAliasee(AliaseeInModule);
AS->setAliaseeGUID(AliaseeGUID);

auto GUID = getValueInfoFromValueId(ValueID);
AS->setOriginalName(GUID.second);
Expand Down Expand Up @@ -5288,9 +5289,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
getValueInfoFromValueId(AliaseeValueId).first.getGUID();
auto AliaseeInModule =
TheIndex.findSummaryInModule(AliaseeGUID, AS->modulePath());
if (!AliaseeInModule)
return error("Alias expects aliasee summary to be parsed");
AS->setAliasee(AliaseeInModule);
AS->setAliaseeGUID(AliaseeGUID);

ValueInfo VI = getValueInfoFromValueId(ValueID).first;
LastSeenGUID = VI.getGUID();
Expand Down
22 changes: 17 additions & 5 deletions lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ class IndexBitcodeWriter : public BitcodeWriterBase {
// 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
// are currently saved in the index in terms of GUID.
forEachSummary([&](GVInfo I) {
forEachSummary([&](GVInfo I, bool) {
GUIDToValueIdMap[I.first] = ++GlobalValueId;
});
}
Expand All @@ -428,12 +428,18 @@ class IndexBitcodeWriter : public BitcodeWriterBase {
void forEachSummary(Functor Callback) {
if (ModuleToSummariesForIndex) {
for (auto &M : *ModuleToSummariesForIndex)
for (auto &Summary : M.second)
Callback(Summary);
for (auto &Summary : M.second) {
Callback(Summary, false);
// Ensure aliasee is handled, e.g. for assigning a valueId,
// even if we are not importing the aliasee directly (the
// imported alias will contain a copy of aliasee).
if (auto *AS = dyn_cast<AliasSummary>(Summary.getSecond()))
Callback({AS->getAliaseeGUID(), &AS->getAliasee()}, true);
}
} else {
for (auto &Summaries : Index)
for (auto &Summary : Summaries.second.SummaryList)
Callback({Summaries.first, Summary.get()});
Callback({Summaries.first, Summary.get()}, false);
}
}

Expand Down Expand Up @@ -3604,14 +3610,20 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
NameVals.clear();
};

forEachSummary([&](GVInfo I) {
forEachSummary([&](GVInfo I, bool IsAliasee) {
GlobalValueSummary *S = I.second;
assert(S);

auto ValueId = getValueId(I.first);
assert(ValueId);
SummaryToValueIdMap[S] = *ValueId;

// If this is invoked for an aliasee, we want to record the above
// mapping, but then not emit a summary entry (if the aliasee is
// to be imported, we will invoke this separately with IsAliasee=false).
if (IsAliasee)
return;

if (auto *AS = dyn_cast<AliasSummary>(S)) {
// Will process aliases as a post-pass because the reader wants all
// global to be loaded first.
Expand Down
2 changes: 1 addition & 1 deletion lib/IR/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ void Value::doRAUW(Value *New, bool NoMetadata) {
if (!NoMetadata && isUsedByMetadata())
ValueAsMetadata::handleRAUW(this, New);

while (!use_empty()) {
while (!materialized_use_empty()) {
Use &U = *UseList;
// Must handle Constants specially, we cannot call replaceUsesOfWith on a
// constant because they are uniqued.
Expand Down
118 changes: 97 additions & 21 deletions lib/Transforms/IPO/FunctionImport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalObject.h"
Expand All @@ -44,7 +45,9 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <cassert>
#include <memory>
#include <set>
Expand Down Expand Up @@ -118,6 +121,12 @@ static cl::opt<std::string>
SummaryFile("summary-file",
cl::desc("The summary file to use for function importing."));

/// Used when testing importing from distributed indexes via opt
// -function-import.
static cl::opt<bool>
ImportAllIndex("import-all-index",
cl::desc("Import all external functions in index."));

// Load lazily a module from \p FileName in \p Context.
static std::unique_ptr<Module> loadFile(const std::string &FileName,
LLVMContext &Context) {
Expand Down Expand Up @@ -172,13 +181,8 @@ selectCallee(const ModuleSummaryIndex &Index,
if (GlobalValue::isInterposableLinkage(GVSummary->linkage()))
// There is no point in importing these, we can't inline them
return false;
if (isa<AliasSummary>(GVSummary))
// Aliases can't point to "available_externally".
// FIXME: we should import alias as available_externally *function*,
// the destination module does not need to know it is an alias.
return false;

auto *Summary = cast<FunctionSummary>(GVSummary);
auto *Summary = cast<FunctionSummary>(GVSummary->getBaseObject());

// If this is a local function, make sure we import the copy
// in the caller's module. The only time a local function can
Expand Down Expand Up @@ -275,9 +279,7 @@ static void computeImportForFunction(
}

// "Resolve" the summary
assert(!isa<AliasSummary>(CalleeSummary) &&
"Unexpected alias in import list");
const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary);
const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary->getBaseObject());

assert(ResolvedCalleeSummary->instCount() <= NewThreshold &&
"selectCallee() didn't honor the threshold");
Expand Down Expand Up @@ -432,6 +434,19 @@ void llvm::ComputeCrossModuleImport(
#endif
}

#ifndef NDEBUG
static void dumpImportListForModule(StringRef ModulePath,
FunctionImporter::ImportMapTy &ImportList) {
DEBUG(dbgs() << "* Module " << ModulePath << " imports from "
<< ImportList.size() << " modules.\n");
for (auto &Src : ImportList) {
auto SrcModName = Src.first();
DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from "
<< SrcModName << "\n");
}
#endif
}

/// Compute all the imports for the given module in the Index.
void llvm::ComputeCrossModuleImportForModule(
StringRef ModulePath, const ModuleSummaryIndex &Index,
Expand All @@ -446,13 +461,34 @@ void llvm::ComputeCrossModuleImportForModule(
ComputeImportForModule(FunctionSummaryMap, Index, ImportList);

#ifndef NDEBUG
DEBUG(dbgs() << "* Module " << ModulePath << " imports from "
<< ImportList.size() << " modules.\n");
for (auto &Src : ImportList) {
auto SrcModName = Src.first();
DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from "
<< SrcModName << "\n");
dumpImportListForModule(ModulePath, ImportList);
#endif
}

// Mark all external summaries in Index for import into the given module.
// Used for distributed builds using a distributed index.
void llvm::ComputeCrossModuleImportForModuleFromIndex(
StringRef ModulePath, const ModuleSummaryIndex &Index,
FunctionImporter::ImportMapTy &ImportList) {
for (auto &GlobalList : Index) {
// Ignore entries for undefined references.
if (GlobalList.second.SummaryList.empty())
continue;

auto GUID = GlobalList.first;
assert(GlobalList.second.SummaryList.size() == 1 &&
"Expected individual combined index to have one summary per GUID");
auto &Summary = GlobalList.second.SummaryList[0];
// Skip the summaries for the importing module. These are included to
// e.g. record required linkage changes.
if (Summary->modulePath() == ModulePath)
continue;
// Doesn't matter what value we plug in to the map, just needs an entry
// to provoke importing by thinBackend.
ImportList[Summary->modulePath()][GUID] = 1;
}
#ifndef NDEBUG
dumpImportListForModule(ModulePath, ImportList);
#endif
}

Expand Down Expand Up @@ -692,6 +728,20 @@ void llvm::thinLTOInternalizeModule(Module &TheModule,
internalizeModule(TheModule, MustPreserveGV);
}

/// Make alias a clone of its aliasee.
static Function *replaceAliasWithAliasee(Module *SrcModule, GlobalAlias *GA) {
Function *Fn = cast<Function>(GA->getBaseObject());

ValueToValueMapTy VMap;
Function *NewFn = CloneFunction(Fn, VMap);
// Clone should use the original alias's linkage and name, and we ensure
// all uses of alias instead use the new clone (casted if necessary).
NewFn->setLinkage(GA->getLinkage());
GA->replaceAllUsesWith(ConstantExpr::getBitCast(NewFn, GA->getType()));
NewFn->takeName(GA);
return NewFn;
}

// Automatically import functions in Module \p DestModule based on the summaries
// index.
Expected<bool> FunctionImporter::importFunctions(
Expand Down Expand Up @@ -761,17 +811,36 @@ Expected<bool> FunctionImporter::importFunctions(
GlobalsToImport.insert(&GV);
}
}
#ifndef NDEBUG
for (GlobalAlias &GA : SrcModule->aliases()) {
if (!GA.hasName())
continue;
auto GUID = GA.getGUID();
assert(!ImportGUIDs.count(GUID) && "Unexpected alias in import list");
DEBUG(dbgs() << "Not importing alias " << GUID
auto Import = ImportGUIDs.count(GUID);
DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing alias " << GUID
<< " " << GA.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (Import) {
if (Error Err = GA.materialize())
return std::move(Err);
// Import alias as a copy of its aliasee.
GlobalObject *Base = GA.getBaseObject();
if (Error Err = Base->materialize())
return std::move(Err);
auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
DEBUG(dbgs() << "Is importing aliasee fn " << Base->getGUID()
<< " " << Base->getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (EnableImportMetadata) {
// Add 'thinlto_src_module' metadata for statistics and debugging.
Fn->setMetadata(
"thinlto_src_module",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getSourceFileName())}));
}
GlobalsToImport.insert(Fn);
}
}
#endif

// Upgrade debug info after we're done materializing all the globals and we
// have loaded all the required metadata!
Expand Down Expand Up @@ -817,8 +886,15 @@ static bool doImportingForModule(Module &M) {

// First step is collecting the import list.
FunctionImporter::ImportMapTy ImportList;
ComputeCrossModuleImportForModule(M.getModuleIdentifier(), *Index,
ImportList);
// If requested, simply import all functions in the index. This is used
// when testing distributed backend handling via the opt tool, when
// we have distributed indexes containing exactly the summaries to import.
if (ImportAllIndex)
ComputeCrossModuleImportForModuleFromIndex(M.getModuleIdentifier(), *Index,
ImportList);
else
ComputeCrossModuleImportForModule(M.getModuleIdentifier(), *Index,
ImportList);

// Conservatively mark all internal values as promoted. This interface is
// only used when doing importing via the function importing pass. The pass
Expand Down
6 changes: 6 additions & 0 deletions test/ThinLTO/X86/Inputs/distributed_import.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ entry:
%0 = load i32, i32* @G
ret i32 %0
}

@analias = alias void (...), bitcast (void ()* @aliasee to void (...)*)
define void @aliasee() {
entry:
ret void
}
6 changes: 6 additions & 0 deletions test/ThinLTO/X86/Inputs/distributed_indexes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ define void @g() {
entry:
ret void
}

@analias = alias void (...), bitcast (void ()* @aliasee to void (...)*)
define void @aliasee() {
entry:
ret void
}
Loading

0 comments on commit 2140d92

Please sign in to comment.