Index: include/llvm/Transforms/IPO/FunctionImport.h =================================================================== --- include/llvm/Transforms/IPO/FunctionImport.h +++ include/llvm/Transforms/IPO/FunctionImport.h @@ -18,23 +18,6 @@ class Module; class FunctionInfoIndex; -/// Helper to load on demand a Module from file and cache it for subsequent -/// queries. It can be used with the FunctionImporter. -class ModuleLazyLoaderCache { - /// The context that will be used for importing. - LLVMContext &Context; - - /// Cache of lazily loaded module for import. - StringMap> ModuleMap; - -public: - /// Create the loader, Module will be initialized in \p Context. - ModuleLazyLoaderCache(LLVMContext &Context) : Context(Context) {} - - /// Retrieve a Module from the cache or lazily load it on demand. - Module &operator()(StringRef FileName); -}; - /// The function importer is automatically importing function from other modules /// based on the provided summary informations. class FunctionImporter { @@ -45,16 +28,17 @@ /// Diagnostic will be sent to this handler. DiagnosticHandlerFunction DiagnosticHandler; - /// Retrieve a Module from the cache or lazily load it on demand. - std::function getLazyModule; + /// Factory function to load a Module for a given identifier + std::function(StringRef Identifier)> ModuleLoader; public: + /// Create a Function Importer. FunctionImporter(const FunctionInfoIndex &Index, DiagnosticHandlerFunction DiagnosticHandler, - std::function ModuleLoader) + std::function(StringRef Identifier)> ModuleLoader) : Index(Index), DiagnosticHandler(DiagnosticHandler), - getLazyModule(ModuleLoader) {} + ModuleLoader(ModuleLoader) {} /// Import functions in Module \p M based on the summary informations. bool importFunctions(Module &M); Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -24,6 +24,9 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/SourceMgr.h" + +#include + using namespace llvm; #define DEBUG_TYPE "function-import" @@ -50,31 +53,99 @@ return Result; } +namespace { +/// Helper to load on demand a Module from file and cache it for subsequent +/// queries. It can be used with the FunctionImporter. +class ModuleLazyLoaderCache { + /// Cache of lazily loaded module for import. + StringMap> ModuleMap; + + /// Retrieve a Module from the cache or lazily load it on demand. + std::function(StringRef FileName)> createLazyModule; + +public: + /// Create the loader, Module will be initialized in \p Context. + ModuleLazyLoaderCache(std::function< + std::unique_ptr(StringRef FileName)> createLazyModule) + : createLazyModule(createLazyModule) {} + + /// Retrieve a Module from the cache or lazily load it on demand. + Module &operator()(StringRef FileName); +}; + // Get a Module for \p FileName from the cache, or load it lazily. -Module &ModuleLazyLoaderCache::operator()(StringRef FileName) { - auto &Module = ModuleMap[FileName]; +Module &ModuleLazyLoaderCache::operator()(StringRef Identifier) { + auto &Module = ModuleMap[Identifier]; if (!Module) - Module = loadFile(FileName, Context); + Module = createLazyModule(Identifier); return *Module; } +} + +//// Get a Module for \p FileName from the cache, or load it lazily. +// 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, +static void findExternalCalls(const Module &DestModule, Function &F, + const FunctionInfoIndex &Index, + StringSet<> &CalledFunctions, SmallVector &Worklist) { + // We need to suffix internal function imported from other modules, prepare + // the suffix ahead of time. + StringRef Suffix; + if (F.getParent() != &DestModule) + Suffix = + (Twine(".llvm.") + + Twine(Index.getModuleId(F.getParent()->getModuleIdentifier()))).str(); + for (auto &BB : F) { for (auto &I : BB) { if (isa(I)) { auto CalledFunction = cast(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()); + if (!CalledFunction || !CalledFunction->hasName()) + continue; + // Ignore intrinsics early + if (CalledFunction->isIntrinsic()) { + assert(CalledFunction->getIntrinsicID() != 0); + continue; } + auto ImportedName = CalledFunction->getName(); + // Rename internal functions + if (CalledFunction->hasInternalLinkage()) { + ImportedName = (ImportedName + Suffix).str(); + } + auto It = CalledFunctions.insert(ImportedName); + if (!It.second) { + DEBUG(dbgs() << DestModule.getModuleIdentifier() << " Ignoring " + << ImportedName << "\n"); + continue; + } +#ifndef NDEBUG + // Ignore functions already present in the destination module + auto *SrcGV = DestModule.getNamedValue(ImportedName); + if (SrcGV) { + assert(isa(SrcGV) && "Name collision during import"); + if (!cast(SrcGV)->isDeclaration()) { + DEBUG(dbgs() << DestModule.getModuleIdentifier() << "Ignoring " + << ImportedName << " already in DestinationModule\n"); + continue; + } + } +#endif // NDEBUG + + Worklist.push_back(It.first->getKey()); + DEBUG(dbgs() << DestModule.getModuleIdentifier() + << " Adding callee for : " << ImportedName << " : " + << F.getName() << "\n"); } } } @@ -82,21 +153,23 @@ // Helper function: given a worklist and an index, will process all the worklist // and import them based on the summary information -static unsigned ProcessImportWorklist( - Module &DestModule, SmallVector &Worklist, - StringSet<> &CalledFunctions, Linker &TheLinker, - const FunctionInfoIndex &Index, - std::function &LazyModuleLoader) { - unsigned ImportCount = 0; +static void +GetImportList(Module &DestModule, SmallVector &Worklist, + StringSet<> &CalledFunctions, + std::unordered_map> & + ModuleToFunctionsToImportMap, + const FunctionInfoIndex &Index, + ModuleLazyLoaderCache &ModuleLoaderCache) { while (!Worklist.empty()) { auto CalledFunctionName = Worklist.pop_back_val(); - DEBUG(dbgs() << "Process import for " << CalledFunctionName << "\n"); + DEBUG(dbgs() << DestModule.getModuleIdentifier() << "Process import for " + << CalledFunctionName << "\n"); // Try to get a summary for this function call. auto InfoList = Index.findFunctionInfoList(CalledFunctionName); if (InfoList == Index.end()) { - DEBUG(dbgs() << "No summary for " << CalledFunctionName - << " Ignoring.\n"); + DEBUG(dbgs() << DestModule.getModuleIdentifier() << "No summary for " + << CalledFunctionName << " Ignoring.\n"); continue; } assert(!InfoList->second.empty() && "No summary, error at import?"); @@ -108,80 +181,73 @@ auto *Summary = Info->functionSummary(); if (!Summary) { // FIXME: in case we are lazyloading summaries, we can do it now. - DEBUG(dbgs() << "Missing summary for " << CalledFunctionName + DEBUG(dbgs() << DestModule.getModuleIdentifier() + << " Missing summary for " << CalledFunctionName << ", error at import?\n"); llvm_unreachable("Missing summary"); } if (Summary->instCount() > ImportInstrLimit) { - DEBUG(dbgs() << "Skip import of " << CalledFunctionName << " with " - << Summary->instCount() << " instructions (limit " - << ImportInstrLimit << ")\n"); + DEBUG(dbgs() << DestModule.getModuleIdentifier() << " Skip import of " + << CalledFunctionName << " with " << Summary->instCount() + << " instructions (limit " << ImportInstrLimit << ")\n"); continue; } // Get the module path from the summary. - auto FileName = Summary->modulePath(); - DEBUG(dbgs() << "Importing " << CalledFunctionName << " from " << FileName - << "\n"); + auto ModuleIdentifier = Summary->modulePath(); + DEBUG(dbgs() << DestModule.getModuleIdentifier() << " Importing " + << CalledFunctionName << " from " << ModuleIdentifier << "\n"); - // Get the module for the import (potentially from the cache). - auto &Module = LazyModuleLoader(FileName); - assert(&Module.getContext() == &DestModule.getContext()); + auto &SrcModule = ModuleLoaderCache(ModuleIdentifier); // The function that we will import! - GlobalValue *SGV = Module.getNamedValue(CalledFunctionName); - StringRef ImportFunctionName = CalledFunctionName; + GlobalValue *SGV = SrcModule.getNamedValue(CalledFunctionName); + if (!SGV) { - // Might be local in source Module, promoted/renamed in DestModule. + // The destination module is referencing function using their renamed name + // when importing a function that was originally local in the source + // module. The source module we have might not have been renamed so we try + // to remove the suffix added during the renaming to recover the original + // name in the source module. std::pair 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 + SGV = SrcModule.getNamedValue(Split.first); + assert(SGV && "Can't find function to import in source module"); } + if (!SGV) { + report_fatal_error(Twine("Can't load function '") + CalledFunctionName + + "' in Module '" + SrcModule.getModuleIdentifier() + + "', error in the summary?\n"); + } + Function *F = dyn_cast(SGV); if (!F && isa(SGV)) { auto *SGA = dyn_cast(SGV); F = dyn_cast(SGA->getBaseObject()); - ImportFunctionName = F->getName(); - } - if (!F) { - errs() << "Can't load function '" << CalledFunctionName << "' in Module '" - << FileName << "', error in the summary?\n"; - llvm_unreachable("Can't load function in Module"); + CalledFunctionName = F->getName(); } + assert(F && "Imported Function is ... not a Function"); // We cannot import weak_any functions/aliases without possibly affecting // the order they are seen and selected by the linker, changing program // semantics. if (SGV->hasWeakAnyLinkage()) { - DEBUG(dbgs() << "Ignoring import request for weak-any " + DEBUG(dbgs() << DestModule.getModuleIdentifier() + << " Ignoring import request for weak-any " << (isa(SGV) ? "function " : "alias ") - << CalledFunctionName << " from " << FileName << "\n"); + << CalledFunctionName << " from " + << SrcModule.getModuleIdentifier() << "\n"); continue; } - // Link in the specified function. - DenseSet FunctionsToImport; - FunctionsToImport.insert(F); - if (TheLinker.linkInModule(Module, Linker::Flags::None, &Index, - &FunctionsToImport)) - report_fatal_error("Function Import: link error"); + // Add the function to the import list + ModuleToFunctionsToImportMap[&SrcModule].insert(F); - // Process the newly imported function and add callees to the worklist. - GlobalValue *NewGV = DestModule.getNamedValue(ImportFunctionName); - assert(NewGV); - Function *NewF = dyn_cast(NewGV); - assert(NewF); - findExternalCalls(*NewF, CalledFunctions, Worklist); - ++ImportCount; + // Process the newly imported functions and add callees to the worklist. + F->materialize(); + findExternalCalls(DestModule, *F, Index, CalledFunctions, Worklist); } - return ImportCount; } // Automatically import functions in Module \p DestModule based on the summaries @@ -190,7 +256,7 @@ // The current implementation imports every called functions that exists in the // summaries index. bool FunctionImporter::importFunctions(Module &DestModule) { - DEBUG(errs() << "Starting import for Module " + DEBUG(dbgs() << "Starting import for Module " << DestModule.getModuleIdentifier() << "\n"); unsigned ImportedCount = 0; @@ -200,7 +266,7 @@ for (auto &F : DestModule) { if (F.isDeclaration() || F.hasFnAttribute(Attribute::OptimizeNone)) continue; - findExternalCalls(F, CalledFunctions, Worklist); + findExternalCalls(DestModule, F, Index, CalledFunctions, Worklist); } if (Worklist.empty()) return false; @@ -210,10 +276,40 @@ // Linker that will be used for importing function Linker TheLinker(DestModule, DiagnosticHandler); - ImportedCount += ProcessImportWorklist(DestModule, Worklist, CalledFunctions, - TheLinker, Index, getLazyModule); + /// For each iteration, ProcessImportWorklist() will empty the Worklist and + /// then fill it with the callees of the newly imported functions, that we'll + /// process again. + /// This workflow is there for efficiency, since batch-importing functions + /// in ProcessImportWorklist helps required by the ModuleLinker. + + // Map of Module -> List of Function to import from the Module + std::unordered_map> + ModuleToFunctionsToImportMap; + + // Analyze the summaries and get the list of functions to import by + // populating ModuleToFunctionsToImportMap + ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader); + GetImportList(DestModule, Worklist, CalledFunctions, + ModuleToFunctionsToImportMap, Index, ModuleLoaderCache); + assert(Worklist.empty() && "Worklist hasn't been flushed in GetImportList"); + + // Do the actual import of functions now, one Module at a time + for (auto &FunctionsToImportPerModule : ModuleToFunctionsToImportMap) { + // Get the module for the import + // Can't cache it for now because the linker mess it up. + auto &FunctionsToImport = FunctionsToImportPerModule.second; + auto *SrcModule = FunctionsToImportPerModule.first; + assert(&DestModule.getContext() == &SrcModule->getContext() && + "Context mismatch"); + + // Link in the specified functions. + if (TheLinker.linkInModule(*SrcModule, Linker::Flags::None, &Index, + &FunctionsToImport)) + report_fatal_error("Function Import: link error"); - DEBUG(errs() << "Imported " << ImportedCount << " functions for Module " + ImportedCount += FunctionsToImport.size(); + } + DEBUG(dbgs() << "Imported " << ImportedCount << " functions for Module " << DestModule.getModuleIdentifier() << "\n"); return ImportedCount; } @@ -276,10 +372,9 @@ } // Perform the import now. - ModuleLazyLoaderCache Loader(M.getContext()); - FunctionImporter Importer(*Index, diagnosticHandler, - [&](StringRef Name) - -> Module &{ return Loader(Name); }); + auto ModuleLoader = + [&M](StringRef FileName) { return loadFile(FileName, M.getContext()); }; + FunctionImporter Importer(*Index, diagnosticHandler, ModuleLoader); return Importer.importFunctions(M); return false;