aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp')
-rw-r--r--contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp318
1 files changed, 196 insertions, 122 deletions
diff --git a/contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp b/contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp
index 233a36d2bc54..b6d6201cd23b 100644
--- a/contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp
+++ b/contrib/llvm/lib/Transforms/IPO/FunctionImport.cpp
@@ -12,30 +12,54 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO/FunctionImport.h"
-
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/IR/AutoUpgrade.h"
-#include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/Linker/Linker.h"
-#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Object/ModuleSymbolTable.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#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"
-
-#define DEBUG_TYPE "function-import"
+#include "llvm/Transforms/Utils/ValueMapper.h"
+#include <cassert>
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <tuple>
+#include <utility>
using namespace llvm;
+#define DEBUG_TYPE "function-import"
+
STATISTIC(NumImportedFunctions, "Number of functions imported");
STATISTIC(NumImportedModules, "Number of modules imported from");
STATISTIC(NumDeadSymbols, "Number of dead stripped symbols in index");
@@ -61,7 +85,7 @@ static cl::opt<float> ImportHotInstrFactor(
"before processing newly imported functions"));
static cl::opt<float> ImportHotMultiplier(
- "import-hot-multiplier", cl::init(3.0), cl::Hidden, cl::value_desc("x"),
+ "import-hot-multiplier", cl::init(10.0), cl::Hidden, cl::value_desc("x"),
cl::desc("Multiply the `import-instr-limit` threshold for hot callsites"));
static cl::opt<float> ImportCriticalMultiplier(
@@ -91,6 +115,18 @@ static cl::opt<bool> EnableImportMetadata(
),
cl::Hidden, cl::desc("Enable import metadata like 'thinlto_src_module'"));
+/// Summary file to use for function importing when using -function-import from
+/// the command line.
+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) {
@@ -109,8 +145,6 @@ static std::unique_ptr<Module> loadFile(const std::string &FileName,
return Result;
}
-namespace {
-
/// Given a list of possible callee implementation for a call site, select one
/// that fits the \p Threshold.
///
@@ -129,21 +163,26 @@ selectCallee(const ModuleSummaryIndex &Index,
CalleeSummaryList,
[&](const std::unique_ptr<GlobalValueSummary> &SummaryPtr) {
auto *GVSummary = SummaryPtr.get();
+ // For SamplePGO, in computeImportForFunction the OriginalId
+ // may have been used to locate the callee summary list (See
+ // comment there).
+ // The mapping from OriginalId to GUID may return a GUID
+ // that corresponds to a static variable. Filter it out here.
+ // This can happen when
+ // 1) There is a call to a library function which is not defined
+ // in the index.
+ // 2) There is a static variable with the OriginalGUID identical
+ // to the GUID of the library function in 1);
+ // When this happens, the logic for SamplePGO kicks in and
+ // the static variable in 2) will be found, which needs to be
+ // filtered out.
+ if (GVSummary->getSummaryKind() == GlobalValueSummary::GlobalVarKind)
+ return false;
if (GlobalValue::isInterposableLinkage(GVSummary->linkage()))
// There is no point in importing these, we can't inline them
return false;
- if (auto *AS = dyn_cast<AliasSummary>(GVSummary)) {
- GVSummary = &AS->getAliasee();
- // Alias can't point to "available_externally". However when we import
- // linkOnceODR the linkage does not change. So we import the alias
- // and aliasee only in this case.
- // FIXME: we should import alias as available_externally *function*,
- // the destination module does need to know it is an alias.
- if (!GlobalValue::isLinkOnceODRLinkage(GVSummary->linkage()))
- 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
@@ -174,9 +213,28 @@ selectCallee(const ModuleSummaryIndex &Index,
return cast<GlobalValueSummary>(It->get());
}
+namespace {
+
using EdgeInfo = std::tuple<const FunctionSummary *, unsigned /* Threshold */,
GlobalValue::GUID>;
+} // anonymous namespace
+
+static ValueInfo
+updateValueInfoForIndirectCalls(const ModuleSummaryIndex &Index, ValueInfo VI) {
+ if (!VI.getSummaryList().empty())
+ return VI;
+ // 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.
+ // FIXME: Consider updating the edges in the graph after building
+ // it, rather than needing to perform this mapping on each walk.
+ auto GUID = Index.getGUIDFromOriginalID(VI.getGUID());
+ if (GUID == 0)
+ return nullptr;
+ return Index.getValueInfo(GUID);
+}
+
/// Compute the list of functions to import for a given caller. Mark these
/// imported functions and the symbols they reference in their source module as
/// exported from their source module.
@@ -191,17 +249,9 @@ static void computeImportForFunction(
DEBUG(dbgs() << " edge -> " << VI.getGUID() << " Threshold:" << Threshold
<< "\n");
- if (VI.getSummaryList().empty()) {
- // 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.
- auto GUID = Index.getGUIDFromOriginalID(VI.getGUID());
- if (GUID == 0)
- continue;
- VI = Index.getValueInfo(GUID);
- if (!VI)
- continue;
- }
+ VI = updateValueInfoForIndirectCalls(Index, VI);
+ if (!VI)
+ continue;
if (DefinedGVSummaries.count(VI.getGUID())) {
DEBUG(dbgs() << "ignored! Target already in destination module.\n");
@@ -227,16 +277,9 @@ static void computeImportForFunction(
DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n");
continue;
}
- // "Resolve" the summary, traversing alias,
- const FunctionSummary *ResolvedCalleeSummary;
- if (isa<AliasSummary>(CalleeSummary)) {
- ResolvedCalleeSummary = cast<FunctionSummary>(
- &cast<AliasSummary>(CalleeSummary)->getAliasee());
- assert(
- GlobalValue::isLinkOnceODRLinkage(ResolvedCalleeSummary->linkage()) &&
- "Unexpected alias to a non-linkonceODR in import list");
- } else
- ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary);
+
+ // "Resolve" the summary
+ const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary->getBaseObject());
assert(ResolvedCalleeSummary->instCount() <= NewThreshold &&
"selectCallee() didn't honor the threshold");
@@ -312,14 +355,12 @@ static void ComputeImportForModule(
DEBUG(dbgs() << "Ignores Dead GUID: " << GVSummary.first << "\n");
continue;
}
- auto *Summary = GVSummary.second;
- if (auto *AS = dyn_cast<AliasSummary>(Summary))
- Summary = &AS->getAliasee();
- auto *FuncSummary = dyn_cast<FunctionSummary>(Summary);
+ auto *FuncSummary =
+ dyn_cast<FunctionSummary>(GVSummary.second->getBaseObject());
if (!FuncSummary)
// Skip import for global variables
continue;
- DEBUG(dbgs() << "Initalize import for " << GVSummary.first << "\n");
+ DEBUG(dbgs() << "Initialize import for " << GVSummary.first << "\n");
computeImportForFunction(*FuncSummary, Index, ImportInstrLimit,
DefinedGVSummaries, Worklist, ImportList,
ExportLists);
@@ -344,8 +385,6 @@ static void ComputeImportForModule(
}
}
-} // anonymous namespace
-
/// Compute all the import and export for every module using the Index.
void llvm::ComputeCrossModuleImport(
const ModuleSummaryIndex &Index,
@@ -395,11 +434,23 @@ 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,
FunctionImporter::ImportMapTy &ImportList) {
-
// Collect the list of functions this module defines.
// GUID -> Summary
GVSummaryMapTy FunctionSummaryMap;
@@ -410,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
}
@@ -453,6 +525,17 @@ void llvm::computeDeadSymbols(
// Make value live and add it to the worklist if it was not live before.
// FIXME: we should only make the prevailing copy live here
auto visit = [&](ValueInfo VI) {
+ // FIXME: If we knew which edges were created for indirect call profiles,
+ // we could skip them here. Any that are live should be reached via
+ // other edges, e.g. reference edges. Otherwise, using a profile collected
+ // on a slightly different binary might provoke preserving, importing
+ // and ultimately promoting calls to functions not linked into this
+ // binary, which increases the binary size unnecessarily. Note that
+ // if this code changes, the importer needs to change so that edges
+ // to functions marked dead are skipped.
+ VI = updateValueInfoForIndirectCalls(Index, VI);
+ if (!VI)
+ return;
for (auto &S : VI.getSummaryList())
if (S->isLive())
return;
@@ -465,17 +548,12 @@ void llvm::computeDeadSymbols(
while (!Worklist.empty()) {
auto VI = Worklist.pop_back_val();
for (auto &Summary : VI.getSummaryList()) {
- for (auto Ref : Summary->refs())
+ GlobalValueSummary *Base = Summary->getBaseObject();
+ for (auto Ref : Base->refs())
visit(Ref);
- if (auto *FS = dyn_cast<FunctionSummary>(Summary.get()))
+ if (auto *FS = dyn_cast<FunctionSummary>(Base))
for (auto Call : FS->calls())
visit(Call.first);
- if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
- auto AliaseeGUID = AS->getAliasee().getOriginalName();
- ValueInfo AliaseeVI = Index.getValueInfo(AliaseeGUID);
- if (AliaseeVI)
- visit(AliaseeVI);
- }
}
}
Index.setWithGlobalValueDeadStripping();
@@ -600,23 +678,9 @@ void llvm::thinLTOResolveWeakForLinkerModule(
/// Run internalization on \p TheModule based on symmary analysis.
void llvm::thinLTOInternalizeModule(Module &TheModule,
const GVSummaryMapTy &DefinedGlobals) {
- // Parse inline ASM and collect the list of symbols that are not defined in
- // the current module.
- StringSet<> AsmUndefinedRefs;
- ModuleSymbolTable::CollectAsmSymbols(
- TheModule,
- [&AsmUndefinedRefs](StringRef Name, object::BasicSymbolRef::Flags Flags) {
- if (Flags & object::BasicSymbolRef::SF_Undefined)
- AsmUndefinedRefs.insert(Name);
- });
-
// Declare a callback for the internalize pass that will ask for every
// candidate GlobalValue if it can be internalized or not.
auto MustPreserveGV = [&](const GlobalValue &GV) -> bool {
- // Can't be internalized if referenced in inline asm.
- if (AsmUndefinedRefs.count(GV.getName()))
- return true;
-
// Lookup the linkage recorded in the summaries during global analysis.
auto GS = DefinedGlobals.find(GV.getGUID());
if (GS == DefinedGlobals.end()) {
@@ -647,12 +711,25 @@ void llvm::thinLTOInternalizeModule(Module &TheModule,
// FIXME: See if we can just internalize directly here via linkage changes
// based on the index, rather than invoking internalizeModule.
- llvm::internalizeModule(TheModule, MustPreserveGV);
+ 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(
Module &DestModule, const FunctionImporter::ImportMapTy &ImportList) {
DEBUG(dbgs() << "Starting import for Module "
@@ -699,10 +776,9 @@ Expected<bool> FunctionImporter::importFunctions(
// Add 'thinlto_src_module' metadata for statistics and debugging.
F.setMetadata(
"thinlto_src_module",
- llvm::MDNode::get(
- DestModule.getContext(),
- {llvm::MDString::get(DestModule.getContext(),
- SrcModule->getSourceFileName())}));
+ MDNode::get(DestModule.getContext(),
+ {MDString::get(DestModule.getContext(),
+ SrcModule->getSourceFileName())}));
}
GlobalsToImport.insert(&F);
}
@@ -722,13 +798,6 @@ Expected<bool> FunctionImporter::importFunctions(
}
}
for (GlobalAlias &GA : SrcModule->aliases()) {
- // FIXME: This should eventually be controlled entirely by the summary.
- if (FunctionImportGlobalProcessing::doImportAsDefinition(
- &GA, &GlobalsToImport)) {
- GlobalsToImport.insert(&GA);
- continue;
- }
-
if (!GA.hasName())
continue;
auto GUID = GA.getGUID();
@@ -737,25 +806,25 @@ Expected<bool> FunctionImporter::importFunctions(
<< " " << GA.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (Import) {
- // Alias can't point to "available_externally". However when we import
- // linkOnceODR the linkage does not change. So we import the alias
- // and aliasee only in this case. This has been handled by
- // computeImportForFunction()
- GlobalObject *GO = GA.getBaseObject();
- assert(GO->hasLinkOnceODRLinkage() &&
- "Unexpected alias to a non-linkonceODR in import list");
-#ifndef NDEBUG
- if (!GlobalsToImport.count(GO))
- DEBUG(dbgs() << " alias triggers importing aliasee " << GO->getGUID()
- << " " << GO->getName() << " from "
- << SrcModule->getSourceFileName() << "\n");
-#endif
- if (Error Err = GO->materialize())
- return std::move(Err);
- GlobalsToImport.insert(GO);
if (Error Err = GA.materialize())
return std::move(Err);
- GlobalsToImport.insert(&GA);
+ // 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);
}
}
@@ -789,12 +858,6 @@ Expected<bool> FunctionImporter::importFunctions(
return ImportedCount;
}
-/// Summary file to use for function importing when using -function-import from
-/// the command line.
-static cl::opt<std::string>
- SummaryFile("summary-file",
- cl::desc("The summary file to use for function importing."));
-
static bool doImportingForModule(Module &M) {
if (SummaryFile.empty())
report_fatal_error("error: -function-import requires -summary-file\n");
@@ -809,8 +872,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
@@ -848,17 +918,18 @@ static bool doImportingForModule(Module &M) {
}
namespace {
+
/// Pass that performs cross-module function import provided a summary file.
class FunctionImportLegacyPass : public ModulePass {
public:
/// Pass identification, replacement for typeid
static char ID;
+ explicit FunctionImportLegacyPass() : ModulePass(ID) {}
+
/// Specify pass name for debug output
StringRef getPassName() const override { return "Function Importing"; }
- explicit FunctionImportLegacyPass() : ModulePass(ID) {}
-
bool runOnModule(Module &M) override {
if (skipModule(M))
return false;
@@ -866,7 +937,8 @@ public:
return doImportingForModule(M);
}
};
-} // anonymous namespace
+
+} // end anonymous namespace
PreservedAnalyses FunctionImportPass::run(Module &M,
ModuleAnalysisManager &AM) {
@@ -881,7 +953,9 @@ INITIALIZE_PASS(FunctionImportLegacyPass, "function-import",
"Summary Based Function Import", false, false)
namespace llvm {
+
Pass *createFunctionImportPass() {
return new FunctionImportLegacyPass();
}
-}
+
+} // end namespace llvm