#define DEBUG_TYPE "function-import"
+/// Limit on instruction count of imported functions.
+static cl::opt<unsigned> ImportInstrLimit(
+ "import-instr-limit", cl::init(100), cl::Hidden, cl::value_desc("N"),
+ cl::desc("Only import functions with less than N instructions"));
+
// Load lazily a module from \p FileName in \p Context.
static std::unique_ptr<Module> loadFile(const std::string &FileName,
LLVMContext &Context) {
}
// Get a Module for \p FileName from the cache, or load it lazily.
-Module &FunctionImporter::getOrLoadModule(StringRef FileName) {
+Module &ModuleLazyLoaderCache::operator()(StringRef FileName) {
auto &Module = ModuleMap[FileName];
if (!Module)
Module = loadFile(FileName, Context);
return *Module;
}
+/// Walk through the instructions in \p F looking for external
+/// calls not already in the \p CalledFunctions set. If any are
+/// found they are added to the \p Worklist for importing.
+static void findExternalCalls(const Function &F, StringSet<> &CalledFunctions,
+ SmallVector<StringRef, 64> &Worklist) {
+ for (auto &BB : F) {
+ for (auto &I : BB) {
+ if (isa<CallInst>(I)) {
+ DEBUG(dbgs() << "Found a call: '" << I << "'\n");
+ auto CalledFunction = cast<CallInst>(I).getCalledFunction();
+ // Insert any new external calls that have not already been
+ // added to set/worklist.
+ if (CalledFunction && CalledFunction->hasName() &&
+ CalledFunction->isDeclaration() &&
+ !CalledFunctions.count(CalledFunction->getName())) {
+ CalledFunctions.insert(CalledFunction->getName());
+ Worklist.push_back(CalledFunction->getName());
+ }
+ }
+ }
+ }
+}
+
// Automatically import functions in Module \p M based on the summaries index.
//
// The current implementation imports every called functions that exists in the
// summaries index.
bool FunctionImporter::importFunctions(Module &M) {
- assert(&Context == &M.getContext());
bool Changed = false;
- /// First step is collecting the called functions and the one defined in this
- /// module.
+ /// First step is collecting the called external functions.
StringSet<> CalledFunctions;
+ SmallVector<StringRef, 64> Worklist;
for (auto &F : M) {
if (F.isDeclaration() || F.hasFnAttribute(Attribute::OptimizeNone))
continue;
- for (auto &BB : F) {
- for (auto &I : BB) {
- if (isa<CallInst>(I)) {
- DEBUG(dbgs() << "Found a call: '" << I << "'\n");
- auto CalledFunction = cast<CallInst>(I).getCalledFunction();
- if (CalledFunction && CalledFunction->hasName() &&
- CalledFunction->isDeclaration())
- CalledFunctions.insert(CalledFunction->getName());
- }
- }
- }
+ findExternalCalls(F, CalledFunctions, Worklist);
}
/// Second step: for every call to an external function, try to import it.
// Linker that will be used for importing function
- Linker L(&M, DiagnosticHandler);
-
- /// Insert initial called function set in a worklist, so that we can add
- /// transively called functions when importing.
- SmallVector<StringRef, 64> Worklist;
- for (auto &CalledFunction : CalledFunctions)
- Worklist.push_back(CalledFunction.first());
+ Linker L(M, DiagnosticHandler);
while (!Worklist.empty()) {
auto CalledFunctionName = Worklist.pop_back_val();
auto *Summary = Info->functionSummary();
if (!Summary) {
// FIXME: in case we are lazyloading summaries, we can do it now.
- dbgs() << "Missing summary for " << CalledFunctionName
- << ", error at import?\n";
+ DEBUG(dbgs() << "Missing summary for " << CalledFunctionName
+ << ", error at import?\n");
llvm_unreachable("Missing summary");
}
- //
- // No profitability notion right now, just import all the time...
- //
+ if (Summary->instCount() > ImportInstrLimit) {
+ DEBUG(dbgs() << "Skip import of " << CalledFunctionName << " with "
+ << Summary->instCount() << " instructions (limit "
+ << ImportInstrLimit << ")\n");
+ continue;
+ }
// Get the module path from the summary.
auto FileName = Summary->modulePath();
<< "\n");
// Get the module for the import (potentially from the cache).
- auto &Module = getOrLoadModule(FileName);
+ auto &Module = getLazyModule(FileName);
+ assert(&Module.getContext() == &M.getContext());
// The function that we will import!
GlobalValue *SGV = Module.getNamedValue(CalledFunctionName);
+ StringRef ImportFunctionName = CalledFunctionName;
+ if (!SGV) {
+ // Might be local in source Module, promoted/renamed in dest Module M.
+ std::pair<StringRef, StringRef> Split =
+ CalledFunctionName.split(".llvm.");
+ SGV = Module.getNamedValue(Split.first);
+#ifndef NDEBUG
+ // Assert that Split.second is module id
+ uint64_t ModuleId;
+ assert(!Split.second.getAsInteger(10, ModuleId));
+ assert(ModuleId == Index.getModuleId(FileName));
+#endif
+ }
Function *F = dyn_cast<Function>(SGV);
if (!F && isa<GlobalAlias>(SGV)) {
auto *SGA = dyn_cast<GlobalAlias>(SGV);
F = dyn_cast<Function>(SGA->getBaseObject());
+ ImportFunctionName = F->getName();
}
if (!F) {
errs() << "Can't load function '" << CalledFunctionName << "' in Module '"
llvm_unreachable("Can't load function in Module");
}
- // We cannot import weak_any functions without possibly affecting the
- // order they are seen and selected by the linker, changing program
+ // We cannot import weak_any functions/aliases without possibly affecting
+ // the order they are seen and selected by the linker, changing program
// semantics.
- if (F->hasWeakAnyLinkage()) {
- DEBUG(dbgs() << "Ignoring import request for weak-any function "
+ if (SGV->hasWeakAnyLinkage()) {
+ DEBUG(dbgs() << "Ignoring import request for weak-any "
+ << (isa<Function>(SGV) ? "function " : "alias ")
<< CalledFunctionName << " from " << FileName << "\n");
continue;
}
// Link in the specified function.
- if (L.linkInModule(&Module, Linker::Flags::None, &Index, F))
+ DenseSet<const GlobalValue *> FunctionsToImport;
+ FunctionsToImport.insert(F);
+ if (L.linkInModule(Module, Linker::Flags::None, &Index,
+ &FunctionsToImport))
report_fatal_error("Function Import: link error");
- // TODO: Process the newly imported function and add callees to the
- // worklist.
+ // Process the newly imported function and add callees to the worklist.
+ GlobalValue *NewGV = M.getNamedValue(ImportFunctionName);
+ assert(NewGV);
+ Function *NewF = dyn_cast<Function>(NewGV);
+ assert(NewF);
+ findExternalCalls(*NewF, CalledFunctions, Worklist);
Changed = true;
}
+
return Changed;
}
}
// Perform the import now.
- FunctionImporter Importer(M.getContext(), *Index, diagnosticHandler);
+ ModuleLazyLoaderCache Loader(M.getContext());
+ FunctionImporter Importer(*Index, diagnosticHandler,
+ [&](StringRef Name)
+ -> Module &{ return Loader(Name); });
return Importer.importFunctions(M);
return false;