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" @@ -33,6 +36,8 @@ "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 loadFile(const std::string &FileName, LLVMContext &Context) { @@ -50,14 +55,42 @@ return Result; } -// 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; +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(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 Identifier) { + auto &Module = ModuleMap[Identifier]; + if (!Module) + 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. @@ -82,12 +115,11 @@ // 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(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"); @@ -121,69 +153,61 @@ } // Get the module path from the summary. - auto FileName = Summary->modulePath(); - DEBUG(dbgs() << "Importing " << CalledFunctionName << " from " << FileName - << "\n"); + auto ModuleIdentifier = Summary->modulePath(); + DEBUG(dbgs() << "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 + CalledFunctionName.split(".llvm."); + 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 " - << (isa(SGV) ? "function " : "alias ") - << CalledFunctionName << " from " << FileName << "\n"); + << (isa(SGV) ? "function " : "alias ") + << 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 functions and add callees to the worklist. + findExternalCalls(*F, CalledFunctions, Worklist); - // 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; } - return ImportCount; } + // Automatically import functions in Module \p DestModule based on the summaries // index. // @@ -210,9 +234,32 @@ // Linker that will be used for importing function Linker TheLinker(DestModule, DiagnosticHandler); - ImportedCount += ProcessImportWorklist(DestModule, Worklist, CalledFunctions, - TheLinker, Index, getLazyModule); + // 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 for each + // module by populating ModuleToFunctionsToImportMap + ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader); + GetImportList(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"); + ImportedCount += FunctionsToImport.size(); + } DEBUG(errs() << "Imported " << ImportedCount << " functions for Module " << DestModule.getModuleIdentifier() << "\n"); return ImportedCount; @@ -276,10 +323,10 @@ } // 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;