142418abaSMehdi Amini //===- FunctionImport.cpp - ThinLTO Summary-based Function Import ---------===//
242418abaSMehdi Amini //
342418abaSMehdi Amini //                     The LLVM Compiler Infrastructure
442418abaSMehdi Amini //
542418abaSMehdi Amini // This file is distributed under the University of Illinois Open Source
642418abaSMehdi Amini // License. See LICENSE.TXT for details.
742418abaSMehdi Amini //
842418abaSMehdi Amini //===----------------------------------------------------------------------===//
942418abaSMehdi Amini //
1042418abaSMehdi Amini // This file implements Function import based on summaries.
1142418abaSMehdi Amini //
1242418abaSMehdi Amini //===----------------------------------------------------------------------===//
1342418abaSMehdi Amini 
1442418abaSMehdi Amini #include "llvm/Transforms/IPO/FunctionImport.h"
1542418abaSMehdi Amini 
1642418abaSMehdi Amini #include "llvm/ADT/StringSet.h"
1742418abaSMehdi Amini #include "llvm/IR/AutoUpgrade.h"
1842418abaSMehdi Amini #include "llvm/IR/DiagnosticPrinter.h"
1942418abaSMehdi Amini #include "llvm/IR/IntrinsicInst.h"
2042418abaSMehdi Amini #include "llvm/IR/Module.h"
2142418abaSMehdi Amini #include "llvm/IRReader/IRReader.h"
2242418abaSMehdi Amini #include "llvm/Linker/Linker.h"
2342418abaSMehdi Amini #include "llvm/Object/FunctionIndexObjectFile.h"
2442418abaSMehdi Amini #include "llvm/Support/CommandLine.h"
2542418abaSMehdi Amini #include "llvm/Support/Debug.h"
2642418abaSMehdi Amini #include "llvm/Support/SourceMgr.h"
2742418abaSMehdi Amini using namespace llvm;
2842418abaSMehdi Amini 
2942418abaSMehdi Amini #define DEBUG_TYPE "function-import"
3042418abaSMehdi Amini 
3139303619STeresa Johnson /// Limit on instruction count of imported functions.
3239303619STeresa Johnson static cl::opt<unsigned> ImportInstrLimit(
3339303619STeresa Johnson     "import-instr-limit", cl::init(100), cl::Hidden, cl::value_desc("N"),
3439303619STeresa Johnson     cl::desc("Only import functions with less than N instructions"));
3539303619STeresa Johnson 
3642418abaSMehdi Amini // Load lazily a module from \p FileName in \p Context.
3742418abaSMehdi Amini static std::unique_ptr<Module> loadFile(const std::string &FileName,
3842418abaSMehdi Amini                                         LLVMContext &Context) {
3942418abaSMehdi Amini   SMDiagnostic Err;
4042418abaSMehdi Amini   DEBUG(dbgs() << "Loading '" << FileName << "'\n");
4142418abaSMehdi Amini   std::unique_ptr<Module> Result = getLazyIRFileModule(FileName, Err, Context);
4242418abaSMehdi Amini   if (!Result) {
4342418abaSMehdi Amini     Err.print("function-import", errs());
4442418abaSMehdi Amini     return nullptr;
4542418abaSMehdi Amini   }
4642418abaSMehdi Amini 
4742418abaSMehdi Amini   Result->materializeMetadata();
4842418abaSMehdi Amini   UpgradeDebugInfo(*Result);
4942418abaSMehdi Amini 
5042418abaSMehdi Amini   return Result;
5142418abaSMehdi Amini }
5242418abaSMehdi Amini 
5342418abaSMehdi Amini // Get a Module for \p FileName from the cache, or load it lazily.
54a11bdc8eSMehdi Amini Module &ModuleLazyLoaderCache::operator()(StringRef FileName) {
5542418abaSMehdi Amini   auto &Module = ModuleMap[FileName];
5642418abaSMehdi Amini   if (!Module)
5742418abaSMehdi Amini     Module = loadFile(FileName, Context);
5842418abaSMehdi Amini   return *Module;
5942418abaSMehdi Amini }
6042418abaSMehdi Amini 
61d450da32STeresa Johnson /// Walk through the instructions in \p F looking for external
62d450da32STeresa Johnson /// calls not already in the \p CalledFunctions set. If any are
63d450da32STeresa Johnson /// found they are added to the \p Worklist for importing.
64d450da32STeresa Johnson static void findExternalCalls(const Function &F, StringSet<> &CalledFunctions,
65d450da32STeresa Johnson                               SmallVector<StringRef, 64> &Worklist) {
66d450da32STeresa Johnson   for (auto &BB : F) {
67d450da32STeresa Johnson     for (auto &I : BB) {
68d450da32STeresa Johnson       if (isa<CallInst>(I)) {
69d450da32STeresa Johnson         auto CalledFunction = cast<CallInst>(I).getCalledFunction();
70d450da32STeresa Johnson         // Insert any new external calls that have not already been
71d450da32STeresa Johnson         // added to set/worklist.
72d450da32STeresa Johnson         if (CalledFunction && CalledFunction->hasName() &&
73d450da32STeresa Johnson             CalledFunction->isDeclaration() &&
74d450da32STeresa Johnson             !CalledFunctions.count(CalledFunction->getName())) {
75d450da32STeresa Johnson           CalledFunctions.insert(CalledFunction->getName());
76d450da32STeresa Johnson           Worklist.push_back(CalledFunction->getName());
77d450da32STeresa Johnson         }
78d450da32STeresa Johnson       }
79d450da32STeresa Johnson     }
80d450da32STeresa Johnson   }
81d450da32STeresa Johnson }
82d450da32STeresa Johnson 
83c8c55170SMehdi Amini // Helper function: given a worklist and an index, will process all the worklist
84c8c55170SMehdi Amini // and import them based on the summary information
85311fef6eSMehdi Amini static unsigned ProcessImportWorklist(
86311fef6eSMehdi Amini     Module &DestModule, SmallVector<StringRef, 64> &Worklist,
87311fef6eSMehdi Amini     StringSet<> &CalledFunctions, Linker &TheLinker,
88311fef6eSMehdi Amini     const FunctionInfoIndex &Index,
89c8c55170SMehdi Amini     std::function<Module &(StringRef FileName)> &LazyModuleLoader) {
90c8c55170SMehdi Amini   unsigned ImportCount = 0;
9142418abaSMehdi Amini   while (!Worklist.empty()) {
9242418abaSMehdi Amini     auto CalledFunctionName = Worklist.pop_back_val();
9342418abaSMehdi Amini     DEBUG(dbgs() << "Process import for " << CalledFunctionName << "\n");
9442418abaSMehdi Amini 
9542418abaSMehdi Amini     // Try to get a summary for this function call.
9642418abaSMehdi Amini     auto InfoList = Index.findFunctionInfoList(CalledFunctionName);
9742418abaSMehdi Amini     if (InfoList == Index.end()) {
9842418abaSMehdi Amini       DEBUG(dbgs() << "No summary for " << CalledFunctionName
9942418abaSMehdi Amini                    << " Ignoring.\n");
10042418abaSMehdi Amini       continue;
10142418abaSMehdi Amini     }
10242418abaSMehdi Amini     assert(!InfoList->second.empty() && "No summary, error at import?");
10342418abaSMehdi Amini 
10442418abaSMehdi Amini     // Comdat can have multiple entries, FIXME: what do we do with them?
10542418abaSMehdi Amini     auto &Info = InfoList->second[0];
10642418abaSMehdi Amini     assert(Info && "Nullptr in list, error importing summaries?\n");
10742418abaSMehdi Amini 
10842418abaSMehdi Amini     auto *Summary = Info->functionSummary();
10942418abaSMehdi Amini     if (!Summary) {
11042418abaSMehdi Amini       // FIXME: in case we are lazyloading summaries, we can do it now.
111430110ccSTeresa Johnson       DEBUG(dbgs() << "Missing summary for  " << CalledFunctionName
112430110ccSTeresa Johnson                    << ", error at import?\n");
11342418abaSMehdi Amini       llvm_unreachable("Missing summary");
11442418abaSMehdi Amini     }
11542418abaSMehdi Amini 
11639303619STeresa Johnson     if (Summary->instCount() > ImportInstrLimit) {
117430110ccSTeresa Johnson       DEBUG(dbgs() << "Skip import of " << CalledFunctionName << " with "
11839303619STeresa Johnson                    << Summary->instCount() << " instructions (limit "
119430110ccSTeresa Johnson                    << ImportInstrLimit << ")\n");
12039303619STeresa Johnson       continue;
12139303619STeresa Johnson     }
12239303619STeresa Johnson 
12342418abaSMehdi Amini     // Get the module path from the summary.
12442418abaSMehdi Amini     auto FileName = Summary->modulePath();
12542418abaSMehdi Amini     DEBUG(dbgs() << "Importing " << CalledFunctionName << " from " << FileName
12642418abaSMehdi Amini                  << "\n");
12742418abaSMehdi Amini 
12842418abaSMehdi Amini     // Get the module for the import (potentially from the cache).
129c8c55170SMehdi Amini     auto &Module = LazyModuleLoader(FileName);
130c8c55170SMehdi Amini     assert(&Module.getContext() == &DestModule.getContext());
13142418abaSMehdi Amini 
13242418abaSMehdi Amini     // The function that we will import!
13342418abaSMehdi Amini     GlobalValue *SGV = Module.getNamedValue(CalledFunctionName);
134130de7afSTeresa Johnson     StringRef ImportFunctionName = CalledFunctionName;
135130de7afSTeresa Johnson     if (!SGV) {
136c8c55170SMehdi Amini       // Might be local in source Module, promoted/renamed in DestModule.
137130de7afSTeresa Johnson       std::pair<StringRef, StringRef> Split =
138130de7afSTeresa Johnson           CalledFunctionName.split(".llvm.");
139130de7afSTeresa Johnson       SGV = Module.getNamedValue(Split.first);
140130de7afSTeresa Johnson #ifndef NDEBUG
141130de7afSTeresa Johnson       // Assert that Split.second is module id
142130de7afSTeresa Johnson       uint64_t ModuleId;
143130de7afSTeresa Johnson       assert(!Split.second.getAsInteger(10, ModuleId));
144130de7afSTeresa Johnson       assert(ModuleId == Index.getModuleId(FileName));
145130de7afSTeresa Johnson #endif
146130de7afSTeresa Johnson     }
14742418abaSMehdi Amini     Function *F = dyn_cast<Function>(SGV);
14842418abaSMehdi Amini     if (!F && isa<GlobalAlias>(SGV)) {
14942418abaSMehdi Amini       auto *SGA = dyn_cast<GlobalAlias>(SGV);
15042418abaSMehdi Amini       F = dyn_cast<Function>(SGA->getBaseObject());
151130de7afSTeresa Johnson       ImportFunctionName = F->getName();
15242418abaSMehdi Amini     }
15342418abaSMehdi Amini     if (!F) {
15442418abaSMehdi Amini       errs() << "Can't load function '" << CalledFunctionName << "' in Module '"
15542418abaSMehdi Amini              << FileName << "', error in the summary?\n";
15642418abaSMehdi Amini       llvm_unreachable("Can't load function in Module");
15742418abaSMehdi Amini     }
15842418abaSMehdi Amini 
15917626654STeresa Johnson     // We cannot import weak_any functions/aliases without possibly affecting
16017626654STeresa Johnson     // the order they are seen and selected by the linker, changing program
16142418abaSMehdi Amini     // semantics.
16217626654STeresa Johnson     if (SGV->hasWeakAnyLinkage()) {
16317626654STeresa Johnson       DEBUG(dbgs() << "Ignoring import request for weak-any "
16417626654STeresa Johnson                    << (isa<Function>(SGV) ? "function " : "alias ")
16542418abaSMehdi Amini                    << CalledFunctionName << " from " << FileName << "\n");
16642418abaSMehdi Amini       continue;
16742418abaSMehdi Amini     }
16842418abaSMehdi Amini 
16942418abaSMehdi Amini     // Link in the specified function.
170ffe2e4aaSMehdi Amini     DenseSet<const GlobalValue *> FunctionsToImport;
171ffe2e4aaSMehdi Amini     FunctionsToImport.insert(F);
172c8c55170SMehdi Amini     if (TheLinker.linkInModule(Module, Linker::Flags::None, &Index,
173ffe2e4aaSMehdi Amini                                &FunctionsToImport))
17442418abaSMehdi Amini       report_fatal_error("Function Import: link error");
17542418abaSMehdi Amini 
176130de7afSTeresa Johnson     // Process the newly imported function and add callees to the worklist.
177c8c55170SMehdi Amini     GlobalValue *NewGV = DestModule.getNamedValue(ImportFunctionName);
178130de7afSTeresa Johnson     assert(NewGV);
179130de7afSTeresa Johnson     Function *NewF = dyn_cast<Function>(NewGV);
180130de7afSTeresa Johnson     assert(NewF);
181d450da32STeresa Johnson     findExternalCalls(*NewF, CalledFunctions, Worklist);
182c8c55170SMehdi Amini     ++ImportCount;
183c8c55170SMehdi Amini   }
184c8c55170SMehdi Amini   return ImportCount;
18542418abaSMehdi Amini }
186ffe2e4aaSMehdi Amini 
187c8c55170SMehdi Amini // Automatically import functions in Module \p DestModule based on the summaries
188c8c55170SMehdi Amini // index.
189c8c55170SMehdi Amini //
190c8c55170SMehdi Amini // The current implementation imports every called functions that exists in the
191c8c55170SMehdi Amini // summaries index.
192c8c55170SMehdi Amini bool FunctionImporter::importFunctions(Module &DestModule) {
193311fef6eSMehdi Amini   DEBUG(errs() << "Starting import for Module "
194311fef6eSMehdi Amini                << DestModule.getModuleIdentifier() << "\n");
195c8c55170SMehdi Amini   unsigned ImportedCount = 0;
196c8c55170SMehdi Amini 
197c8c55170SMehdi Amini   /// First step is collecting the called external functions.
198c8c55170SMehdi Amini   StringSet<> CalledFunctions;
199c8c55170SMehdi Amini   SmallVector<StringRef, 64> Worklist;
200c8c55170SMehdi Amini   for (auto &F : DestModule) {
201c8c55170SMehdi Amini     if (F.isDeclaration() || F.hasFnAttribute(Attribute::OptimizeNone))
202c8c55170SMehdi Amini       continue;
203c8c55170SMehdi Amini     findExternalCalls(F, CalledFunctions, Worklist);
204c8c55170SMehdi Amini   }
205c8c55170SMehdi Amini   if (Worklist.empty())
206c8c55170SMehdi Amini     return false;
207c8c55170SMehdi Amini 
208c8c55170SMehdi Amini   /// Second step: for every call to an external function, try to import it.
209c8c55170SMehdi Amini 
210c8c55170SMehdi Amini   // Linker that will be used for importing function
211c8c55170SMehdi Amini   Linker TheLinker(DestModule, DiagnosticHandler);
212c8c55170SMehdi Amini 
213311fef6eSMehdi Amini   ImportedCount += ProcessImportWorklist(DestModule, Worklist, CalledFunctions,
214311fef6eSMehdi Amini                                          TheLinker, Index, getLazyModule);
215c8c55170SMehdi Amini 
216c8c55170SMehdi Amini   DEBUG(errs() << "Imported " << ImportedCount << " functions for Module "
217c8c55170SMehdi Amini                << DestModule.getModuleIdentifier() << "\n");
218c8c55170SMehdi Amini   return ImportedCount;
21942418abaSMehdi Amini }
22042418abaSMehdi Amini 
22142418abaSMehdi Amini /// Summary file to use for function importing when using -function-import from
22242418abaSMehdi Amini /// the command line.
22342418abaSMehdi Amini static cl::opt<std::string>
22442418abaSMehdi Amini     SummaryFile("summary-file",
22542418abaSMehdi Amini                 cl::desc("The summary file to use for function importing."));
22642418abaSMehdi Amini 
22742418abaSMehdi Amini static void diagnosticHandler(const DiagnosticInfo &DI) {
22842418abaSMehdi Amini   raw_ostream &OS = errs();
22942418abaSMehdi Amini   DiagnosticPrinterRawOStream DP(OS);
23042418abaSMehdi Amini   DI.print(DP);
23142418abaSMehdi Amini   OS << '\n';
23242418abaSMehdi Amini }
23342418abaSMehdi Amini 
23442418abaSMehdi Amini /// Parse the function index out of an IR file and return the function
23542418abaSMehdi Amini /// index object if found, or nullptr if not.
23642418abaSMehdi Amini static std::unique_ptr<FunctionInfoIndex>
23742418abaSMehdi Amini getFunctionIndexForFile(StringRef Path, std::string &Error,
23842418abaSMehdi Amini                         DiagnosticHandlerFunction DiagnosticHandler) {
23942418abaSMehdi Amini   std::unique_ptr<MemoryBuffer> Buffer;
24042418abaSMehdi Amini   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
24142418abaSMehdi Amini       MemoryBuffer::getFile(Path);
24242418abaSMehdi Amini   if (std::error_code EC = BufferOrErr.getError()) {
24342418abaSMehdi Amini     Error = EC.message();
24442418abaSMehdi Amini     return nullptr;
24542418abaSMehdi Amini   }
24642418abaSMehdi Amini   Buffer = std::move(BufferOrErr.get());
24742418abaSMehdi Amini   ErrorOr<std::unique_ptr<object::FunctionIndexObjectFile>> ObjOrErr =
24842418abaSMehdi Amini       object::FunctionIndexObjectFile::create(Buffer->getMemBufferRef(),
24942418abaSMehdi Amini                                               DiagnosticHandler);
25042418abaSMehdi Amini   if (std::error_code EC = ObjOrErr.getError()) {
25142418abaSMehdi Amini     Error = EC.message();
25242418abaSMehdi Amini     return nullptr;
25342418abaSMehdi Amini   }
25442418abaSMehdi Amini   return (*ObjOrErr)->takeIndex();
25542418abaSMehdi Amini }
25642418abaSMehdi Amini 
25742418abaSMehdi Amini /// Pass that performs cross-module function import provided a summary file.
25842418abaSMehdi Amini class FunctionImportPass : public ModulePass {
259*5fcbdb71STeresa Johnson   /// Optional function summary index to use for importing, otherwise
260*5fcbdb71STeresa Johnson   /// the summary-file option must be specified.
261*5fcbdb71STeresa Johnson   FunctionInfoIndex *Index;
26242418abaSMehdi Amini 
26342418abaSMehdi Amini public:
26442418abaSMehdi Amini   /// Pass identification, replacement for typeid
26542418abaSMehdi Amini   static char ID;
26642418abaSMehdi Amini 
267*5fcbdb71STeresa Johnson   /// Specify pass name for debug output
268*5fcbdb71STeresa Johnson   const char *getPassName() const override {
269*5fcbdb71STeresa Johnson     return "Function Importing";
270*5fcbdb71STeresa Johnson   }
271*5fcbdb71STeresa Johnson 
272*5fcbdb71STeresa Johnson   explicit FunctionImportPass(FunctionInfoIndex *Index = nullptr)
273*5fcbdb71STeresa Johnson       : ModulePass(ID), Index(Index) {}
27442418abaSMehdi Amini 
27542418abaSMehdi Amini   bool runOnModule(Module &M) override {
276*5fcbdb71STeresa Johnson     if (SummaryFile.empty() && !Index)
277*5fcbdb71STeresa Johnson       report_fatal_error("error: -function-import requires -summary-file or "
278*5fcbdb71STeresa Johnson                          "file from frontend\n");
279*5fcbdb71STeresa Johnson     std::unique_ptr<FunctionInfoIndex> IndexPtr;
280*5fcbdb71STeresa Johnson     if (!SummaryFile.empty()) {
281*5fcbdb71STeresa Johnson       if (Index)
282*5fcbdb71STeresa Johnson         report_fatal_error("error: -summary-file and index from frontend\n");
28342418abaSMehdi Amini       std::string Error;
284*5fcbdb71STeresa Johnson       IndexPtr = getFunctionIndexForFile(SummaryFile, Error, diagnosticHandler);
285*5fcbdb71STeresa Johnson       if (!IndexPtr) {
286*5fcbdb71STeresa Johnson         errs() << "Error loading file '" << SummaryFile << "': " << Error
287*5fcbdb71STeresa Johnson                << "\n";
28842418abaSMehdi Amini         return false;
28942418abaSMehdi Amini       }
290*5fcbdb71STeresa Johnson       Index = IndexPtr.get();
291*5fcbdb71STeresa Johnson     }
29242418abaSMehdi Amini 
29342418abaSMehdi Amini     // Perform the import now.
294a11bdc8eSMehdi Amini     ModuleLazyLoaderCache Loader(M.getContext());
295a11bdc8eSMehdi Amini     FunctionImporter Importer(*Index, diagnosticHandler,
296a11bdc8eSMehdi Amini                               [&](StringRef Name)
297a11bdc8eSMehdi Amini                                   -> Module &{ return Loader(Name); });
29842418abaSMehdi Amini     return Importer.importFunctions(M);
29942418abaSMehdi Amini 
30042418abaSMehdi Amini     return false;
30142418abaSMehdi Amini   }
30242418abaSMehdi Amini };
30342418abaSMehdi Amini 
30442418abaSMehdi Amini char FunctionImportPass::ID = 0;
30542418abaSMehdi Amini INITIALIZE_PASS_BEGIN(FunctionImportPass, "function-import",
30642418abaSMehdi Amini                       "Summary Based Function Import", false, false)
30742418abaSMehdi Amini INITIALIZE_PASS_END(FunctionImportPass, "function-import",
30842418abaSMehdi Amini                     "Summary Based Function Import", false, false)
30942418abaSMehdi Amini 
31042418abaSMehdi Amini namespace llvm {
311*5fcbdb71STeresa Johnson Pass *createFunctionImportPass(FunctionInfoIndex *Index = nullptr) {
312*5fcbdb71STeresa Johnson   return new FunctionImportPass(Index);
313*5fcbdb71STeresa Johnson }
31442418abaSMehdi Amini }
315