109467b48Spatrick //===- llvm-lto: a simple command-line program to link modules with LTO ---===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This program takes in a list of bitcode files, links them, performs link-time
1009467b48Spatrick // optimization, and outputs an object file.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick 
1409467b48Spatrick #include "llvm-c/lto.h"
1509467b48Spatrick #include "llvm/ADT/ArrayRef.h"
1609467b48Spatrick #include "llvm/ADT/STLExtras.h"
1709467b48Spatrick #include "llvm/ADT/SmallString.h"
1809467b48Spatrick #include "llvm/ADT/StringExtras.h"
1909467b48Spatrick #include "llvm/ADT/StringRef.h"
2009467b48Spatrick #include "llvm/ADT/StringSet.h"
2109467b48Spatrick #include "llvm/ADT/Twine.h"
2209467b48Spatrick #include "llvm/Bitcode/BitcodeReader.h"
2309467b48Spatrick #include "llvm/Bitcode/BitcodeWriter.h"
24097a140dSpatrick #include "llvm/CodeGen/CommandFlags.h"
2509467b48Spatrick #include "llvm/IR/DiagnosticInfo.h"
2609467b48Spatrick #include "llvm/IR/DiagnosticPrinter.h"
2709467b48Spatrick #include "llvm/IR/LLVMContext.h"
2809467b48Spatrick #include "llvm/IR/Module.h"
2909467b48Spatrick #include "llvm/IR/ModuleSummaryIndex.h"
3009467b48Spatrick #include "llvm/IR/Verifier.h"
3109467b48Spatrick #include "llvm/IRReader/IRReader.h"
3209467b48Spatrick #include "llvm/LTO/legacy/LTOCodeGenerator.h"
3309467b48Spatrick #include "llvm/LTO/legacy/LTOModule.h"
3409467b48Spatrick #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
3509467b48Spatrick #include "llvm/Support/Allocator.h"
3609467b48Spatrick #include "llvm/Support/Casting.h"
3709467b48Spatrick #include "llvm/Support/CommandLine.h"
3809467b48Spatrick #include "llvm/Support/Error.h"
3909467b48Spatrick #include "llvm/Support/ErrorHandling.h"
4009467b48Spatrick #include "llvm/Support/ErrorOr.h"
4109467b48Spatrick #include "llvm/Support/FileSystem.h"
4209467b48Spatrick #include "llvm/Support/InitLLVM.h"
4309467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
4409467b48Spatrick #include "llvm/Support/Path.h"
4509467b48Spatrick #include "llvm/Support/SourceMgr.h"
4609467b48Spatrick #include "llvm/Support/TargetSelect.h"
4709467b48Spatrick #include "llvm/Support/ToolOutputFile.h"
4809467b48Spatrick #include "llvm/Support/raw_ostream.h"
49*d415bd75Srobert #include "llvm/Support/WithColor.h"
5009467b48Spatrick #include "llvm/Target/TargetOptions.h"
5109467b48Spatrick #include <algorithm>
5209467b48Spatrick #include <cassert>
5309467b48Spatrick #include <cstdint>
5409467b48Spatrick #include <cstdlib>
5509467b48Spatrick #include <list>
5609467b48Spatrick #include <map>
5709467b48Spatrick #include <memory>
5809467b48Spatrick #include <string>
5909467b48Spatrick #include <system_error>
6009467b48Spatrick #include <tuple>
6109467b48Spatrick #include <utility>
6209467b48Spatrick #include <vector>
6309467b48Spatrick 
6409467b48Spatrick using namespace llvm;
6509467b48Spatrick 
66097a140dSpatrick static codegen::RegisterCodeGenFlags CGF;
67097a140dSpatrick 
6873471bf0Spatrick static cl::OptionCategory LTOCategory("LTO Options");
6973471bf0Spatrick 
7009467b48Spatrick static cl::opt<char>
7173471bf0Spatrick     OptLevel("O",
7273471bf0Spatrick              cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
7309467b48Spatrick                       "(default = '-O2')"),
74*d415bd75Srobert              cl::Prefix, cl::init('2'), cl::cat(LTOCategory));
7509467b48Spatrick 
7609467b48Spatrick static cl::opt<bool>
7709467b48Spatrick     IndexStats("thinlto-index-stats",
7809467b48Spatrick                cl::desc("Print statistic for the index in every input files"),
7973471bf0Spatrick                cl::init(false), cl::cat(LTOCategory));
8009467b48Spatrick 
8109467b48Spatrick static cl::opt<bool> DisableVerify(
8209467b48Spatrick     "disable-verify", cl::init(false),
8373471bf0Spatrick     cl::desc("Do not run the verifier during the optimization pipeline"),
8473471bf0Spatrick     cl::cat(LTOCategory));
8509467b48Spatrick 
8609467b48Spatrick static cl::opt<bool> EnableFreestanding(
8709467b48Spatrick     "lto-freestanding", cl::init(false),
8873471bf0Spatrick     cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
8973471bf0Spatrick     cl::cat(LTOCategory));
9009467b48Spatrick 
9109467b48Spatrick static cl::opt<bool> UseDiagnosticHandler(
9209467b48Spatrick     "use-diagnostic-handler", cl::init(false),
9373471bf0Spatrick     cl::desc("Use a diagnostic handler to test the handler interface"),
9473471bf0Spatrick     cl::cat(LTOCategory));
9509467b48Spatrick 
9609467b48Spatrick static cl::opt<bool>
9709467b48Spatrick     ThinLTO("thinlto", cl::init(false),
9873471bf0Spatrick             cl::desc("Only write combined global index for ThinLTO backends"),
9973471bf0Spatrick             cl::cat(LTOCategory));
10009467b48Spatrick 
10109467b48Spatrick enum ThinLTOModes {
10209467b48Spatrick   THINLINK,
10309467b48Spatrick   THINDISTRIBUTE,
10409467b48Spatrick   THINEMITIMPORTS,
10509467b48Spatrick   THINPROMOTE,
10609467b48Spatrick   THINIMPORT,
10709467b48Spatrick   THININTERNALIZE,
10809467b48Spatrick   THINOPT,
10909467b48Spatrick   THINCODEGEN,
11009467b48Spatrick   THINALL
11109467b48Spatrick };
11209467b48Spatrick 
11309467b48Spatrick cl::opt<ThinLTOModes> ThinLTOMode(
11409467b48Spatrick     "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),
11509467b48Spatrick     cl::values(
11609467b48Spatrick         clEnumValN(
11709467b48Spatrick             THINLINK, "thinlink",
11809467b48Spatrick             "ThinLink: produces the index by linking only the summaries."),
11909467b48Spatrick         clEnumValN(THINDISTRIBUTE, "distributedindexes",
12009467b48Spatrick                    "Produces individual indexes for distributed backends."),
12109467b48Spatrick         clEnumValN(THINEMITIMPORTS, "emitimports",
12209467b48Spatrick                    "Emit imports files for distributed backends."),
12309467b48Spatrick         clEnumValN(THINPROMOTE, "promote",
12409467b48Spatrick                    "Perform pre-import promotion (requires -thinlto-index)."),
12573471bf0Spatrick         clEnumValN(THINIMPORT, "import",
12673471bf0Spatrick                    "Perform both promotion and "
12709467b48Spatrick                    "cross-module importing (requires "
12809467b48Spatrick                    "-thinlto-index)."),
12909467b48Spatrick         clEnumValN(THININTERNALIZE, "internalize",
13009467b48Spatrick                    "Perform internalization driven by -exported-symbol "
13109467b48Spatrick                    "(requires -thinlto-index)."),
13209467b48Spatrick         clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),
13309467b48Spatrick         clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),
13473471bf0Spatrick         clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),
13573471bf0Spatrick     cl::cat(LTOCategory));
13609467b48Spatrick 
13709467b48Spatrick static cl::opt<std::string>
13809467b48Spatrick     ThinLTOIndex("thinlto-index",
13909467b48Spatrick                  cl::desc("Provide the index produced by a ThinLink, required "
14073471bf0Spatrick                           "to perform the promotion and/or importing."),
14173471bf0Spatrick                  cl::cat(LTOCategory));
14209467b48Spatrick 
14309467b48Spatrick static cl::opt<std::string> ThinLTOPrefixReplace(
14409467b48Spatrick     "thinlto-prefix-replace",
14509467b48Spatrick     cl::desc("Control where files for distributed backends are "
14609467b48Spatrick              "created. Expects 'oldprefix;newprefix' and if path "
14709467b48Spatrick              "prefix of output file is oldprefix it will be "
14873471bf0Spatrick              "replaced with newprefix."),
14973471bf0Spatrick     cl::cat(LTOCategory));
15009467b48Spatrick 
15109467b48Spatrick static cl::opt<std::string> ThinLTOModuleId(
15209467b48Spatrick     "thinlto-module-id",
15309467b48Spatrick     cl::desc("For the module ID for the file to process, useful to "
15473471bf0Spatrick              "match what is in the index."),
15573471bf0Spatrick     cl::cat(LTOCategory));
15609467b48Spatrick 
15773471bf0Spatrick static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",
15873471bf0Spatrick                                             cl::desc("Enable ThinLTO caching."),
15973471bf0Spatrick                                             cl::cat(LTOCategory));
16009467b48Spatrick 
16173471bf0Spatrick static cl::opt<int> ThinLTOCachePruningInterval(
16273471bf0Spatrick     "thinlto-cache-pruning-interval", cl::init(1200),
16373471bf0Spatrick     cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));
16409467b48Spatrick 
16509467b48Spatrick static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
16609467b48Spatrick     "thinlto-cache-max-size-bytes",
16773471bf0Spatrick     cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),
16873471bf0Spatrick     cl::cat(LTOCategory));
16909467b48Spatrick 
17073471bf0Spatrick static cl::opt<int> ThinLTOCacheMaxSizeFiles(
17173471bf0Spatrick     "thinlto-cache-max-size-files", cl::init(1000000),
17273471bf0Spatrick     cl::desc("Set ThinLTO cache pruning directory maximum number of files."),
17373471bf0Spatrick     cl::cat(LTOCategory));
17409467b48Spatrick 
17573471bf0Spatrick static cl::opt<unsigned> ThinLTOCacheEntryExpiration(
17673471bf0Spatrick     "thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,
17773471bf0Spatrick     cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));
17809467b48Spatrick 
17909467b48Spatrick static cl::opt<std::string> ThinLTOSaveTempsPrefix(
18009467b48Spatrick     "thinlto-save-temps",
18109467b48Spatrick     cl::desc("Save ThinLTO temp files using filenames created by adding "
18273471bf0Spatrick              "suffixes to the given file path prefix."),
18373471bf0Spatrick     cl::cat(LTOCategory));
18409467b48Spatrick 
18509467b48Spatrick static cl::opt<std::string> ThinLTOGeneratedObjectsDir(
18609467b48Spatrick     "thinlto-save-objects",
18709467b48Spatrick     cl::desc("Save ThinLTO generated object files using filenames created in "
18873471bf0Spatrick              "the given directory."),
18973471bf0Spatrick     cl::cat(LTOCategory));
19073471bf0Spatrick 
19173471bf0Spatrick static cl::opt<bool> SaveLinkedModuleFile(
19273471bf0Spatrick     "save-linked-module", cl::init(false),
19373471bf0Spatrick     cl::desc("Write linked LTO module to file before optimize"),
19473471bf0Spatrick     cl::cat(LTOCategory));
19509467b48Spatrick 
19609467b48Spatrick static cl::opt<bool>
19709467b48Spatrick     SaveModuleFile("save-merged-module", cl::init(false),
19873471bf0Spatrick                    cl::desc("Write merged LTO module to file before CodeGen"),
19973471bf0Spatrick                    cl::cat(LTOCategory));
20009467b48Spatrick 
20109467b48Spatrick static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
20273471bf0Spatrick                                             cl::desc("<input bitcode files>"),
20373471bf0Spatrick                                             cl::cat(LTOCategory));
20409467b48Spatrick 
20509467b48Spatrick static cl::opt<std::string> OutputFilename("o", cl::init(""),
20609467b48Spatrick                                            cl::desc("Override output filename"),
20773471bf0Spatrick                                            cl::value_desc("filename"),
20873471bf0Spatrick                                            cl::cat(LTOCategory));
20909467b48Spatrick 
21009467b48Spatrick static cl::list<std::string> ExportedSymbols(
21109467b48Spatrick     "exported-symbol",
21209467b48Spatrick     cl::desc("List of symbols to export from the resulting object file"),
213*d415bd75Srobert     cl::cat(LTOCategory));
21409467b48Spatrick 
21509467b48Spatrick static cl::list<std::string>
21609467b48Spatrick     DSOSymbols("dso-symbol",
21709467b48Spatrick                cl::desc("Symbol to put in the symtab in the resulting dso"),
218*d415bd75Srobert                cl::cat(LTOCategory));
21909467b48Spatrick 
22009467b48Spatrick static cl::opt<bool> ListSymbolsOnly(
22109467b48Spatrick     "list-symbols-only", cl::init(false),
22273471bf0Spatrick     cl::desc("Instead of running LTO, list the symbols in each IR file"),
22373471bf0Spatrick     cl::cat(LTOCategory));
22409467b48Spatrick 
22509467b48Spatrick static cl::opt<bool> ListDependentLibrariesOnly(
22609467b48Spatrick     "list-dependent-libraries-only", cl::init(false),
22773471bf0Spatrick     cl::desc(
22873471bf0Spatrick         "Instead of running LTO, list the dependent libraries in each IR file"),
22973471bf0Spatrick     cl::cat(LTOCategory));
23009467b48Spatrick 
231*d415bd75Srobert static cl::opt<bool> QueryHasCtorDtor(
232*d415bd75Srobert     "query-hasCtorDtor", cl::init(false),
233*d415bd75Srobert     cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));
234*d415bd75Srobert 
23573471bf0Spatrick static cl::opt<bool>
23673471bf0Spatrick     SetMergedModule("set-merged-module", cl::init(false),
23773471bf0Spatrick                     cl::desc("Use the first input module as the merged module"),
23873471bf0Spatrick                     cl::cat(LTOCategory));
23909467b48Spatrick 
24009467b48Spatrick static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
24173471bf0Spatrick                                      cl::desc("Number of backend threads"),
24273471bf0Spatrick                                      cl::cat(LTOCategory));
24309467b48Spatrick 
24409467b48Spatrick static cl::opt<bool> RestoreGlobalsLinkage(
24509467b48Spatrick     "restore-linkage", cl::init(false),
24673471bf0Spatrick     cl::desc("Restore original linkage of globals prior to CodeGen"),
24773471bf0Spatrick     cl::cat(LTOCategory));
24809467b48Spatrick 
24909467b48Spatrick static cl::opt<bool> CheckHasObjC(
25009467b48Spatrick     "check-for-objc", cl::init(false),
25173471bf0Spatrick     cl::desc("Only check if the module has objective-C defined in it"),
25273471bf0Spatrick     cl::cat(LTOCategory));
25309467b48Spatrick 
254097a140dSpatrick static cl::opt<bool> PrintMachOCPUOnly(
255097a140dSpatrick     "print-macho-cpu-only", cl::init(false),
25673471bf0Spatrick     cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),
25773471bf0Spatrick     cl::cat(LTOCategory));
25873471bf0Spatrick 
25973471bf0Spatrick static cl::opt<bool>
26073471bf0Spatrick     DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,
26173471bf0Spatrick                      cl::desc("Print pass management debugging information"),
26273471bf0Spatrick                      cl::cat(LTOCategory));
263097a140dSpatrick 
264*d415bd75Srobert static cl::opt<bool>
265*d415bd75Srobert     LTOSaveBeforeOpt("lto-save-before-opt", cl::init(false),
266*d415bd75Srobert                      cl::desc("Save the IR before running optimizations"));
267*d415bd75Srobert 
26809467b48Spatrick namespace {
26909467b48Spatrick 
27009467b48Spatrick struct ModuleInfo {
271*d415bd75Srobert   BitVector CanBeHidden;
27209467b48Spatrick };
27309467b48Spatrick 
27409467b48Spatrick } // end anonymous namespace
27509467b48Spatrick 
handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,const char * Msg,void *)27609467b48Spatrick static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
27709467b48Spatrick                               const char *Msg, void *) {
27809467b48Spatrick   errs() << "llvm-lto: ";
27909467b48Spatrick   switch (Severity) {
28009467b48Spatrick   case LTO_DS_NOTE:
28109467b48Spatrick     errs() << "note: ";
28209467b48Spatrick     break;
28309467b48Spatrick   case LTO_DS_REMARK:
28409467b48Spatrick     errs() << "remark: ";
28509467b48Spatrick     break;
28609467b48Spatrick   case LTO_DS_ERROR:
28709467b48Spatrick     errs() << "error: ";
28809467b48Spatrick     break;
28909467b48Spatrick   case LTO_DS_WARNING:
29009467b48Spatrick     errs() << "warning: ";
29109467b48Spatrick     break;
29209467b48Spatrick   }
29309467b48Spatrick   errs() << Msg << "\n";
29409467b48Spatrick }
29509467b48Spatrick 
29609467b48Spatrick static std::string CurrentActivity;
29709467b48Spatrick 
29809467b48Spatrick namespace {
29909467b48Spatrick   struct LLVMLTODiagnosticHandler : public DiagnosticHandler {
handleDiagnostics__anon0c592d740211::LLVMLTODiagnosticHandler30009467b48Spatrick     bool handleDiagnostics(const DiagnosticInfo &DI) override {
30109467b48Spatrick       raw_ostream &OS = errs();
30209467b48Spatrick       OS << "llvm-lto: ";
30309467b48Spatrick       switch (DI.getSeverity()) {
30409467b48Spatrick       case DS_Error:
30509467b48Spatrick         OS << "error";
30609467b48Spatrick         break;
30709467b48Spatrick       case DS_Warning:
30809467b48Spatrick         OS << "warning";
30909467b48Spatrick         break;
31009467b48Spatrick       case DS_Remark:
31109467b48Spatrick         OS << "remark";
31209467b48Spatrick         break;
31309467b48Spatrick       case DS_Note:
31409467b48Spatrick         OS << "note";
31509467b48Spatrick         break;
31609467b48Spatrick       }
31709467b48Spatrick       if (!CurrentActivity.empty())
31809467b48Spatrick         OS << ' ' << CurrentActivity;
31909467b48Spatrick       OS << ": ";
32009467b48Spatrick 
32109467b48Spatrick       DiagnosticPrinterRawOStream DP(OS);
32209467b48Spatrick       DI.print(DP);
32309467b48Spatrick       OS << '\n';
32409467b48Spatrick 
32509467b48Spatrick       if (DI.getSeverity() == DS_Error)
32609467b48Spatrick         exit(1);
32709467b48Spatrick       return true;
32809467b48Spatrick     }
32909467b48Spatrick   };
33009467b48Spatrick   }
33109467b48Spatrick 
error(const Twine & Msg)33209467b48Spatrick static void error(const Twine &Msg) {
33309467b48Spatrick   errs() << "llvm-lto: " << Msg << '\n';
33409467b48Spatrick   exit(1);
33509467b48Spatrick }
33609467b48Spatrick 
error(std::error_code EC,const Twine & Prefix)33709467b48Spatrick static void error(std::error_code EC, const Twine &Prefix) {
33809467b48Spatrick   if (EC)
33909467b48Spatrick     error(Prefix + ": " + EC.message());
34009467b48Spatrick }
34109467b48Spatrick 
34209467b48Spatrick template <typename T>
error(const ErrorOr<T> & V,const Twine & Prefix)34309467b48Spatrick static void error(const ErrorOr<T> &V, const Twine &Prefix) {
34409467b48Spatrick   error(V.getError(), Prefix);
34509467b48Spatrick }
34609467b48Spatrick 
maybeVerifyModule(const Module & Mod)34709467b48Spatrick static void maybeVerifyModule(const Module &Mod) {
34809467b48Spatrick   if (!DisableVerify && verifyModule(Mod, &errs()))
34909467b48Spatrick     error("Broken Module");
35009467b48Spatrick }
35109467b48Spatrick 
35209467b48Spatrick static std::unique_ptr<LTOModule>
getLocalLTOModule(StringRef Path,std::unique_ptr<MemoryBuffer> & Buffer,const TargetOptions & Options)35309467b48Spatrick getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
35409467b48Spatrick                   const TargetOptions &Options) {
35509467b48Spatrick   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
35609467b48Spatrick       MemoryBuffer::getFile(Path);
35709467b48Spatrick   error(BufferOrErr, "error loading file '" + Path + "'");
35809467b48Spatrick   Buffer = std::move(BufferOrErr.get());
35909467b48Spatrick   CurrentActivity = ("loading file '" + Path + "'").str();
36009467b48Spatrick   std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
36109467b48Spatrick   Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
36209467b48Spatrick                                 true);
36309467b48Spatrick   ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
36409467b48Spatrick       std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),
36509467b48Spatrick       Options, Path);
36609467b48Spatrick   CurrentActivity = "";
36709467b48Spatrick   maybeVerifyModule((*Ret)->getModule());
36809467b48Spatrick   return std::move(*Ret);
36909467b48Spatrick }
37009467b48Spatrick 
37109467b48Spatrick /// Print some statistics on the index for each input files.
printIndexStats()37273471bf0Spatrick static void printIndexStats() {
37309467b48Spatrick   for (auto &Filename : InputFilenames) {
37409467b48Spatrick     ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
37509467b48Spatrick     std::unique_ptr<ModuleSummaryIndex> Index =
37609467b48Spatrick         ExitOnErr(getModuleSummaryIndexForFile(Filename));
37709467b48Spatrick     // Skip files without a module summary.
37809467b48Spatrick     if (!Index)
379*d415bd75Srobert       report_fatal_error(Twine(Filename) + " does not contain an index");
38009467b48Spatrick 
38109467b48Spatrick     unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
38209467b48Spatrick     for (auto &Summaries : *Index) {
38309467b48Spatrick       for (auto &Summary : Summaries.second.SummaryList) {
38409467b48Spatrick         Refs += Summary->refs().size();
38509467b48Spatrick         if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
38609467b48Spatrick           Functions++;
38709467b48Spatrick           Calls += FuncSummary->calls().size();
38809467b48Spatrick         } else if (isa<AliasSummary>(Summary.get()))
38909467b48Spatrick           Alias++;
39009467b48Spatrick         else
39109467b48Spatrick           Globals++;
39209467b48Spatrick       }
39309467b48Spatrick     }
39409467b48Spatrick     outs() << "Index " << Filename << " contains "
39509467b48Spatrick            << (Alias + Globals + Functions) << " nodes (" << Functions
39609467b48Spatrick            << " functions, " << Alias << " alias, " << Globals
39709467b48Spatrick            << " globals) and " << (Calls + Refs) << " edges (" << Refs
39809467b48Spatrick            << " refs and " << Calls << " calls)\n";
39909467b48Spatrick   }
40009467b48Spatrick }
40109467b48Spatrick 
402*d415bd75Srobert /// Load each IR file and dump certain information based on active flags.
40309467b48Spatrick ///
40409467b48Spatrick /// The main point here is to provide lit-testable coverage for the LTOModule
405*d415bd75Srobert /// functionality that's exposed by the C API. Moreover, this provides testing
406*d415bd75Srobert /// coverage for modules that have been created in their own contexts.
testLTOModule(const TargetOptions & Options)407*d415bd75Srobert static void testLTOModule(const TargetOptions &Options) {
40809467b48Spatrick   for (auto &Filename : InputFilenames) {
40909467b48Spatrick     std::unique_ptr<MemoryBuffer> Buffer;
41009467b48Spatrick     std::unique_ptr<LTOModule> Module =
41109467b48Spatrick         getLocalLTOModule(Filename, Buffer, Options);
41209467b48Spatrick 
413*d415bd75Srobert     if (ListSymbolsOnly) {
41409467b48Spatrick       // List the symbols.
41509467b48Spatrick       outs() << Filename << ":\n";
41609467b48Spatrick       for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
41709467b48Spatrick         outs() << Module->getSymbolName(I) << "\n";
41809467b48Spatrick     }
419*d415bd75Srobert     if (QueryHasCtorDtor)
420*d415bd75Srobert       outs() << Filename
421*d415bd75Srobert              << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")
422*d415bd75Srobert              << "\n";
423*d415bd75Srobert   }
42409467b48Spatrick }
42509467b48Spatrick 
loadFile(StringRef Filename)42609467b48Spatrick static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
42709467b48Spatrick     ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
42809467b48Spatrick         "': ");
42909467b48Spatrick     return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
43009467b48Spatrick }
43109467b48Spatrick 
listDependentLibraries()43209467b48Spatrick static void listDependentLibraries() {
43309467b48Spatrick   for (auto &Filename : InputFilenames) {
43409467b48Spatrick     auto Buffer = loadFile(Filename);
43509467b48Spatrick     std::string E;
43609467b48Spatrick     std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
43709467b48Spatrick         Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),
43809467b48Spatrick         E));
43909467b48Spatrick     if (!Input)
44009467b48Spatrick       error(E);
44109467b48Spatrick 
44209467b48Spatrick     // List the dependent libraries.
44309467b48Spatrick     outs() << Filename << ":\n";
44409467b48Spatrick     for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());
44509467b48Spatrick          I != C; ++I) {
44609467b48Spatrick       size_t L = 0;
44709467b48Spatrick       const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);
44809467b48Spatrick       assert(S);
44909467b48Spatrick       outs() << StringRef(S, L) << "\n";
45009467b48Spatrick     }
45109467b48Spatrick   }
45209467b48Spatrick }
45309467b48Spatrick 
printMachOCPUOnly()454097a140dSpatrick static void printMachOCPUOnly() {
455097a140dSpatrick   LLVMContext Context;
456097a140dSpatrick   Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
457097a140dSpatrick                                true);
45873471bf0Spatrick   TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
459097a140dSpatrick   for (auto &Filename : InputFilenames) {
460097a140dSpatrick     ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
461097a140dSpatrick         LTOModule::createFromFile(Context, Filename, Options);
462097a140dSpatrick     if (!ModuleOrErr)
463097a140dSpatrick       error(ModuleOrErr, "llvm-lto: ");
464097a140dSpatrick 
465097a140dSpatrick     Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();
466097a140dSpatrick     Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();
467097a140dSpatrick     if (!CPUType)
468097a140dSpatrick       error("Error while printing mach-o cputype: " +
469097a140dSpatrick             toString(CPUType.takeError()));
470097a140dSpatrick     if (!CPUSubType)
471097a140dSpatrick       error("Error while printing mach-o cpusubtype: " +
472097a140dSpatrick             toString(CPUSubType.takeError()));
473097a140dSpatrick     outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n",
474097a140dSpatrick                            Filename.c_str(), *CPUType, *CPUSubType);
475097a140dSpatrick   }
476097a140dSpatrick }
477097a140dSpatrick 
47809467b48Spatrick /// Create a combined index file from the input IR files and write it.
47909467b48Spatrick ///
48009467b48Spatrick /// This is meant to enable testing of ThinLTO combined index generation,
48109467b48Spatrick /// currently available via the gold plugin via -thinlto.
createCombinedModuleSummaryIndex()48209467b48Spatrick static void createCombinedModuleSummaryIndex() {
48309467b48Spatrick   ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
48409467b48Spatrick   uint64_t NextModuleId = 0;
48509467b48Spatrick   for (auto &Filename : InputFilenames) {
48609467b48Spatrick     ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
48709467b48Spatrick     std::unique_ptr<MemoryBuffer> MB =
48809467b48Spatrick         ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
48909467b48Spatrick     ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, NextModuleId++));
49009467b48Spatrick   }
491*d415bd75Srobert   // In order to use this index for testing, specifically import testing, we
492*d415bd75Srobert   // need to update any indirect call edges created from SamplePGO, so that they
493*d415bd75Srobert   // point to the correct GUIDs.
494*d415bd75Srobert   updateIndirectCalls(CombinedIndex);
49509467b48Spatrick   std::error_code EC;
49609467b48Spatrick   assert(!OutputFilename.empty());
49709467b48Spatrick   raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
49809467b48Spatrick                     sys::fs::OpenFlags::OF_None);
49909467b48Spatrick   error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
500*d415bd75Srobert   writeIndexToFile(CombinedIndex, OS);
50109467b48Spatrick   OS.close();
50209467b48Spatrick }
50309467b48Spatrick 
50409467b48Spatrick /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
50509467b48Spatrick /// \p NewPrefix strings, if it was specified.
getThinLTOOldAndNewPrefix(std::string & OldPrefix,std::string & NewPrefix)50609467b48Spatrick static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
50709467b48Spatrick                                       std::string &NewPrefix) {
50809467b48Spatrick   assert(ThinLTOPrefixReplace.empty() ||
50973471bf0Spatrick          ThinLTOPrefixReplace.find(';') != StringRef::npos);
51009467b48Spatrick   StringRef PrefixReplace = ThinLTOPrefixReplace;
51109467b48Spatrick   std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");
51209467b48Spatrick   OldPrefix = Split.first.str();
51309467b48Spatrick   NewPrefix = Split.second.str();
51409467b48Spatrick }
51509467b48Spatrick 
51609467b48Spatrick /// Given the original \p Path to an output file, replace any path
51709467b48Spatrick /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
51809467b48Spatrick /// resulting directory if it does not yet exist.
getThinLTOOutputFile(const std::string & Path,const std::string & OldPrefix,const std::string & NewPrefix)51909467b48Spatrick static std::string getThinLTOOutputFile(const std::string &Path,
52009467b48Spatrick                                         const std::string &OldPrefix,
52109467b48Spatrick                                         const std::string &NewPrefix) {
52209467b48Spatrick   if (OldPrefix.empty() && NewPrefix.empty())
52309467b48Spatrick     return Path;
52409467b48Spatrick   SmallString<128> NewPath(Path);
52509467b48Spatrick   llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
52609467b48Spatrick   StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
52709467b48Spatrick   if (!ParentPath.empty()) {
52809467b48Spatrick     // Make sure the new directory exists, creating it if necessary.
52909467b48Spatrick     if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
53009467b48Spatrick       error(EC, "error creating the directory '" + ParentPath + "'");
53109467b48Spatrick   }
532097a140dSpatrick   return std::string(NewPath.str());
53309467b48Spatrick }
53409467b48Spatrick 
53509467b48Spatrick namespace thinlto {
53609467b48Spatrick 
53709467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>>
loadAllFilesForIndex(const ModuleSummaryIndex & Index)53809467b48Spatrick loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
53909467b48Spatrick   std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
54009467b48Spatrick 
54109467b48Spatrick   for (auto &ModPath : Index.modulePaths()) {
54209467b48Spatrick     const auto &Filename = ModPath.first();
54309467b48Spatrick     std::string CurrentActivity = ("loading file '" + Filename + "'").str();
54409467b48Spatrick     auto InputOrErr = MemoryBuffer::getFile(Filename);
54509467b48Spatrick     error(InputOrErr, "error " + CurrentActivity);
54609467b48Spatrick     InputBuffers.push_back(std::move(*InputOrErr));
54709467b48Spatrick   }
54809467b48Spatrick   return InputBuffers;
54909467b48Spatrick }
55009467b48Spatrick 
loadCombinedIndex()55109467b48Spatrick std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
55209467b48Spatrick   if (ThinLTOIndex.empty())
55309467b48Spatrick     report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");
55409467b48Spatrick   ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +
55509467b48Spatrick                         "': ");
55609467b48Spatrick   return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));
55709467b48Spatrick }
55809467b48Spatrick 
loadInputFile(MemoryBufferRef Buffer)55909467b48Spatrick static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
56009467b48Spatrick   ExitOnError ExitOnErr("llvm-lto: error loading input '" +
56109467b48Spatrick                         Buffer.getBufferIdentifier().str() + "': ");
56209467b48Spatrick   return ExitOnErr(lto::InputFile::create(Buffer));
56309467b48Spatrick }
56409467b48Spatrick 
loadModuleFromInput(lto::InputFile & File,LLVMContext & CTX)56509467b48Spatrick static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
56609467b48Spatrick                                                    LLVMContext &CTX) {
56709467b48Spatrick   auto &Mod = File.getSingleBitcodeModule();
56809467b48Spatrick   auto ModuleOrErr = Mod.parseModule(CTX);
56909467b48Spatrick   if (!ModuleOrErr) {
57009467b48Spatrick     handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
57109467b48Spatrick       SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
57209467b48Spatrick                                       SourceMgr::DK_Error, EIB.message());
57309467b48Spatrick       Err.print("llvm-lto", errs());
57409467b48Spatrick     });
57509467b48Spatrick     report_fatal_error("Can't load module, abort.");
57609467b48Spatrick   }
57709467b48Spatrick   maybeVerifyModule(**ModuleOrErr);
57809467b48Spatrick   if (ThinLTOModuleId.getNumOccurrences()) {
57909467b48Spatrick     if (InputFilenames.size() != 1)
58009467b48Spatrick       report_fatal_error("Can't override the module id for multiple files");
58109467b48Spatrick     (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
58209467b48Spatrick   }
58309467b48Spatrick   return std::move(*ModuleOrErr);
58409467b48Spatrick }
58509467b48Spatrick 
writeModuleToFile(Module & TheModule,StringRef Filename)58609467b48Spatrick static void writeModuleToFile(Module &TheModule, StringRef Filename) {
58709467b48Spatrick   std::error_code EC;
58809467b48Spatrick   raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);
58909467b48Spatrick   error(EC, "error opening the file '" + Filename + "'");
59009467b48Spatrick   maybeVerifyModule(TheModule);
59109467b48Spatrick   WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);
59209467b48Spatrick }
59309467b48Spatrick 
59409467b48Spatrick class ThinLTOProcessing {
59509467b48Spatrick public:
59609467b48Spatrick   ThinLTOCodeGenerator ThinGenerator;
59709467b48Spatrick 
ThinLTOProcessing(const TargetOptions & Options)59809467b48Spatrick   ThinLTOProcessing(const TargetOptions &Options) {
599097a140dSpatrick     ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());
60009467b48Spatrick     ThinGenerator.setTargetOptions(Options);
60109467b48Spatrick     ThinGenerator.setCacheDir(ThinLTOCacheDir);
60209467b48Spatrick     ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);
60309467b48Spatrick     ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
60409467b48Spatrick     ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
60509467b48Spatrick     ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
60609467b48Spatrick     ThinGenerator.setFreestanding(EnableFreestanding);
60773471bf0Spatrick     ThinGenerator.setDebugPassManager(DebugPassManager);
60809467b48Spatrick 
60909467b48Spatrick     // Add all the exported symbols to the table of symbols to preserve.
61009467b48Spatrick     for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
61109467b48Spatrick       ThinGenerator.preserveSymbol(ExportedSymbols[i]);
61209467b48Spatrick   }
61309467b48Spatrick 
run()61409467b48Spatrick   void run() {
61509467b48Spatrick     switch (ThinLTOMode) {
61609467b48Spatrick     case THINLINK:
61709467b48Spatrick       return thinLink();
61809467b48Spatrick     case THINDISTRIBUTE:
61909467b48Spatrick       return distributedIndexes();
62009467b48Spatrick     case THINEMITIMPORTS:
62109467b48Spatrick       return emitImports();
62209467b48Spatrick     case THINPROMOTE:
62309467b48Spatrick       return promote();
62409467b48Spatrick     case THINIMPORT:
62509467b48Spatrick       return import();
62609467b48Spatrick     case THININTERNALIZE:
62709467b48Spatrick       return internalize();
62809467b48Spatrick     case THINOPT:
62909467b48Spatrick       return optimize();
63009467b48Spatrick     case THINCODEGEN:
63109467b48Spatrick       return codegen();
63209467b48Spatrick     case THINALL:
63309467b48Spatrick       return runAll();
63409467b48Spatrick     }
63509467b48Spatrick   }
63609467b48Spatrick 
63709467b48Spatrick private:
63809467b48Spatrick   /// Load the input files, create the combined index, and write it out.
thinLink()63909467b48Spatrick   void thinLink() {
64009467b48Spatrick     // Perform "ThinLink": just produce the index
64109467b48Spatrick     if (OutputFilename.empty())
64209467b48Spatrick       report_fatal_error(
64309467b48Spatrick           "OutputFilename is necessary to store the combined index.\n");
64409467b48Spatrick 
64509467b48Spatrick     LLVMContext Ctx;
64609467b48Spatrick     std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
64709467b48Spatrick     for (unsigned i = 0; i < InputFilenames.size(); ++i) {
64809467b48Spatrick       auto &Filename = InputFilenames[i];
64909467b48Spatrick       std::string CurrentActivity = "loading file '" + Filename + "'";
65009467b48Spatrick       auto InputOrErr = MemoryBuffer::getFile(Filename);
65109467b48Spatrick       error(InputOrErr, "error " + CurrentActivity);
65209467b48Spatrick       InputBuffers.push_back(std::move(*InputOrErr));
65309467b48Spatrick       ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
65409467b48Spatrick     }
65509467b48Spatrick 
65609467b48Spatrick     auto CombinedIndex = ThinGenerator.linkCombinedIndex();
65709467b48Spatrick     if (!CombinedIndex)
65809467b48Spatrick       report_fatal_error("ThinLink didn't create an index");
65909467b48Spatrick     std::error_code EC;
66009467b48Spatrick     raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
66109467b48Spatrick     error(EC, "error opening the file '" + OutputFilename + "'");
662*d415bd75Srobert     writeIndexToFile(*CombinedIndex, OS);
66309467b48Spatrick   }
66409467b48Spatrick 
66509467b48Spatrick   /// Load the combined index from disk, then compute and generate
66609467b48Spatrick   /// individual index files suitable for ThinLTO distributed backend builds
66709467b48Spatrick   /// on the files mentioned on the command line (these must match the index
66809467b48Spatrick   /// content).
distributedIndexes()66909467b48Spatrick   void distributedIndexes() {
67009467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
67109467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
67209467b48Spatrick                          "input files, do not provide an output filename and "
67309467b48Spatrick                          "the output files will be suffixed from the input "
67409467b48Spatrick                          "ones.");
67509467b48Spatrick 
67609467b48Spatrick     std::string OldPrefix, NewPrefix;
67709467b48Spatrick     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
67809467b48Spatrick 
67909467b48Spatrick     auto Index = loadCombinedIndex();
68009467b48Spatrick     for (auto &Filename : InputFilenames) {
68109467b48Spatrick       LLVMContext Ctx;
68209467b48Spatrick       auto Buffer = loadFile(Filename);
68309467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
68409467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
68509467b48Spatrick 
68609467b48Spatrick       // Build a map of module to the GUIDs and summary objects that should
68709467b48Spatrick       // be written to its index.
68809467b48Spatrick       std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
68909467b48Spatrick       ThinGenerator.gatherImportedSummariesForModule(
69009467b48Spatrick           *TheModule, *Index, ModuleToSummariesForIndex, *Input);
69109467b48Spatrick 
69209467b48Spatrick       std::string OutputName = OutputFilename;
69309467b48Spatrick       if (OutputName.empty()) {
69409467b48Spatrick         OutputName = Filename + ".thinlto.bc";
69509467b48Spatrick       }
69609467b48Spatrick       OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
69709467b48Spatrick       std::error_code EC;
69809467b48Spatrick       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
69909467b48Spatrick       error(EC, "error opening the file '" + OutputName + "'");
700*d415bd75Srobert       writeIndexToFile(*Index, OS, &ModuleToSummariesForIndex);
70109467b48Spatrick     }
70209467b48Spatrick   }
70309467b48Spatrick 
70409467b48Spatrick   /// Load the combined index from disk, compute the imports, and emit
70509467b48Spatrick   /// the import file lists for each module to disk.
emitImports()70609467b48Spatrick   void emitImports() {
70709467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
70809467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
70909467b48Spatrick                          "input files, do not provide an output filename and "
71009467b48Spatrick                          "the output files will be suffixed from the input "
71109467b48Spatrick                          "ones.");
71209467b48Spatrick 
71309467b48Spatrick     std::string OldPrefix, NewPrefix;
71409467b48Spatrick     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
71509467b48Spatrick 
71609467b48Spatrick     auto Index = loadCombinedIndex();
71709467b48Spatrick     for (auto &Filename : InputFilenames) {
71809467b48Spatrick       LLVMContext Ctx;
71909467b48Spatrick       auto Buffer = loadFile(Filename);
72009467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
72109467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
72209467b48Spatrick       std::string OutputName = OutputFilename;
72309467b48Spatrick       if (OutputName.empty()) {
72409467b48Spatrick         OutputName = Filename + ".imports";
72509467b48Spatrick       }
72609467b48Spatrick       OutputName =
72709467b48Spatrick           getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
72809467b48Spatrick       ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);
72909467b48Spatrick     }
73009467b48Spatrick   }
73109467b48Spatrick 
73209467b48Spatrick   /// Load the combined index from disk, then load every file referenced by
73309467b48Spatrick   /// the index and add them to the generator, finally perform the promotion
73409467b48Spatrick   /// on the files mentioned on the command line (these must match the index
73509467b48Spatrick   /// content).
promote()73609467b48Spatrick   void promote() {
73709467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
73809467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
73909467b48Spatrick                          "input files, do not provide an output filename and "
74009467b48Spatrick                          "the output files will be suffixed from the input "
74109467b48Spatrick                          "ones.");
74209467b48Spatrick 
74309467b48Spatrick     auto Index = loadCombinedIndex();
74409467b48Spatrick     for (auto &Filename : InputFilenames) {
74509467b48Spatrick       LLVMContext Ctx;
74609467b48Spatrick       auto Buffer = loadFile(Filename);
74709467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
74809467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
74909467b48Spatrick 
75009467b48Spatrick       ThinGenerator.promote(*TheModule, *Index, *Input);
75109467b48Spatrick 
75209467b48Spatrick       std::string OutputName = OutputFilename;
75309467b48Spatrick       if (OutputName.empty()) {
75409467b48Spatrick         OutputName = Filename + ".thinlto.promoted.bc";
75509467b48Spatrick       }
75609467b48Spatrick       writeModuleToFile(*TheModule, OutputName);
75709467b48Spatrick     }
75809467b48Spatrick   }
75909467b48Spatrick 
76009467b48Spatrick   /// Load the combined index from disk, then load every file referenced by
76109467b48Spatrick   /// the index and add them to the generator, then performs the promotion and
76209467b48Spatrick   /// cross module importing on the files mentioned on the command line
76309467b48Spatrick   /// (these must match the index content).
import()76409467b48Spatrick   void import() {
76509467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
76609467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
76709467b48Spatrick                          "input files, do not provide an output filename and "
76809467b48Spatrick                          "the output files will be suffixed from the input "
76909467b48Spatrick                          "ones.");
77009467b48Spatrick 
77109467b48Spatrick     auto Index = loadCombinedIndex();
77209467b48Spatrick     auto InputBuffers = loadAllFilesForIndex(*Index);
77309467b48Spatrick     for (auto &MemBuffer : InputBuffers)
77409467b48Spatrick       ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
77509467b48Spatrick                               MemBuffer->getBuffer());
77609467b48Spatrick 
77709467b48Spatrick     for (auto &Filename : InputFilenames) {
77809467b48Spatrick       LLVMContext Ctx;
77909467b48Spatrick       auto Buffer = loadFile(Filename);
78009467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
78109467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
78209467b48Spatrick 
78309467b48Spatrick       ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);
78409467b48Spatrick 
78509467b48Spatrick       std::string OutputName = OutputFilename;
78609467b48Spatrick       if (OutputName.empty()) {
78709467b48Spatrick         OutputName = Filename + ".thinlto.imported.bc";
78809467b48Spatrick       }
78909467b48Spatrick       writeModuleToFile(*TheModule, OutputName);
79009467b48Spatrick     }
79109467b48Spatrick   }
79209467b48Spatrick 
internalize()79309467b48Spatrick   void internalize() {
79409467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
79509467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
79609467b48Spatrick                          "input files, do not provide an output filename and "
79709467b48Spatrick                          "the output files will be suffixed from the input "
79809467b48Spatrick                          "ones.");
79909467b48Spatrick 
80009467b48Spatrick     if (ExportedSymbols.empty())
80109467b48Spatrick       errs() << "Warning: -internalize will not perform without "
80209467b48Spatrick                 "-exported-symbol\n";
80309467b48Spatrick 
80409467b48Spatrick     auto Index = loadCombinedIndex();
80509467b48Spatrick     auto InputBuffers = loadAllFilesForIndex(*Index);
80609467b48Spatrick     for (auto &MemBuffer : InputBuffers)
80709467b48Spatrick       ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
80809467b48Spatrick                               MemBuffer->getBuffer());
80909467b48Spatrick 
81009467b48Spatrick     for (auto &Filename : InputFilenames) {
81109467b48Spatrick       LLVMContext Ctx;
81209467b48Spatrick       auto Buffer = loadFile(Filename);
81309467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
81409467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
81509467b48Spatrick 
81609467b48Spatrick       ThinGenerator.internalize(*TheModule, *Index, *Input);
81709467b48Spatrick 
81809467b48Spatrick       std::string OutputName = OutputFilename;
81909467b48Spatrick       if (OutputName.empty()) {
82009467b48Spatrick         OutputName = Filename + ".thinlto.internalized.bc";
82109467b48Spatrick       }
82209467b48Spatrick       writeModuleToFile(*TheModule, OutputName);
82309467b48Spatrick     }
82409467b48Spatrick   }
82509467b48Spatrick 
optimize()82609467b48Spatrick   void optimize() {
82709467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
82809467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
82909467b48Spatrick                          "input files, do not provide an output filename and "
83009467b48Spatrick                          "the output files will be suffixed from the input "
83109467b48Spatrick                          "ones.");
83209467b48Spatrick     if (!ThinLTOIndex.empty())
83309467b48Spatrick       errs() << "Warning: -thinlto-index ignored for optimize stage";
83409467b48Spatrick 
83509467b48Spatrick     for (auto &Filename : InputFilenames) {
83609467b48Spatrick       LLVMContext Ctx;
83709467b48Spatrick       auto Buffer = loadFile(Filename);
83809467b48Spatrick       auto Input = loadInputFile(Buffer->getMemBufferRef());
83909467b48Spatrick       auto TheModule = loadModuleFromInput(*Input, Ctx);
84009467b48Spatrick 
84109467b48Spatrick       ThinGenerator.optimize(*TheModule);
84209467b48Spatrick 
84309467b48Spatrick       std::string OutputName = OutputFilename;
84409467b48Spatrick       if (OutputName.empty()) {
84509467b48Spatrick         OutputName = Filename + ".thinlto.imported.bc";
84609467b48Spatrick       }
84709467b48Spatrick       writeModuleToFile(*TheModule, OutputName);
84809467b48Spatrick     }
84909467b48Spatrick   }
85009467b48Spatrick 
codegen()85109467b48Spatrick   void codegen() {
85209467b48Spatrick     if (InputFilenames.size() != 1 && !OutputFilename.empty())
85309467b48Spatrick       report_fatal_error("Can't handle a single output filename and multiple "
85409467b48Spatrick                          "input files, do not provide an output filename and "
85509467b48Spatrick                          "the output files will be suffixed from the input "
85609467b48Spatrick                          "ones.");
85709467b48Spatrick     if (!ThinLTOIndex.empty())
85809467b48Spatrick       errs() << "Warning: -thinlto-index ignored for codegen stage";
85909467b48Spatrick 
86009467b48Spatrick     std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
86109467b48Spatrick     for (auto &Filename : InputFilenames) {
86209467b48Spatrick       LLVMContext Ctx;
86309467b48Spatrick       auto InputOrErr = MemoryBuffer::getFile(Filename);
86409467b48Spatrick       error(InputOrErr, "error " + CurrentActivity);
86509467b48Spatrick       InputBuffers.push_back(std::move(*InputOrErr));
86609467b48Spatrick       ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
86709467b48Spatrick     }
86809467b48Spatrick     ThinGenerator.setCodeGenOnly(true);
86909467b48Spatrick     ThinGenerator.run();
87009467b48Spatrick     for (auto BinName :
87109467b48Spatrick          zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {
87209467b48Spatrick       std::string OutputName = OutputFilename;
87309467b48Spatrick       if (OutputName.empty())
87409467b48Spatrick         OutputName = std::get<1>(BinName) + ".thinlto.o";
87509467b48Spatrick       else if (OutputName == "-") {
87609467b48Spatrick         outs() << std::get<0>(BinName)->getBuffer();
87709467b48Spatrick         return;
87809467b48Spatrick       }
87909467b48Spatrick 
88009467b48Spatrick       std::error_code EC;
88109467b48Spatrick       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
88209467b48Spatrick       error(EC, "error opening the file '" + OutputName + "'");
88309467b48Spatrick       OS << std::get<0>(BinName)->getBuffer();
88409467b48Spatrick     }
88509467b48Spatrick   }
88609467b48Spatrick 
88709467b48Spatrick   /// Full ThinLTO process
runAll()88809467b48Spatrick   void runAll() {
88909467b48Spatrick     if (!OutputFilename.empty())
89009467b48Spatrick       report_fatal_error("Do not provide an output filename for ThinLTO "
89109467b48Spatrick                          " processing, the output files will be suffixed from "
89209467b48Spatrick                          "the input ones.");
89309467b48Spatrick 
89409467b48Spatrick     if (!ThinLTOIndex.empty())
89509467b48Spatrick       errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
89609467b48Spatrick 
89709467b48Spatrick     LLVMContext Ctx;
89809467b48Spatrick     std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
89909467b48Spatrick     for (unsigned i = 0; i < InputFilenames.size(); ++i) {
90009467b48Spatrick       auto &Filename = InputFilenames[i];
90109467b48Spatrick       std::string CurrentActivity = "loading file '" + Filename + "'";
90209467b48Spatrick       auto InputOrErr = MemoryBuffer::getFile(Filename);
90309467b48Spatrick       error(InputOrErr, "error " + CurrentActivity);
90409467b48Spatrick       InputBuffers.push_back(std::move(*InputOrErr));
90509467b48Spatrick       ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
90609467b48Spatrick     }
90709467b48Spatrick 
90809467b48Spatrick     if (!ThinLTOSaveTempsPrefix.empty())
90909467b48Spatrick       ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
91009467b48Spatrick 
91109467b48Spatrick     if (!ThinLTOGeneratedObjectsDir.empty()) {
91209467b48Spatrick       ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
91309467b48Spatrick       ThinGenerator.run();
91409467b48Spatrick       return;
91509467b48Spatrick     }
91609467b48Spatrick 
91709467b48Spatrick     ThinGenerator.run();
91809467b48Spatrick 
91909467b48Spatrick     auto &Binaries = ThinGenerator.getProducedBinaries();
92009467b48Spatrick     if (Binaries.size() != InputFilenames.size())
92109467b48Spatrick       report_fatal_error("Number of output objects does not match the number "
92209467b48Spatrick                          "of inputs");
92309467b48Spatrick 
92409467b48Spatrick     for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
92509467b48Spatrick       auto OutputName = InputFilenames[BufID] + ".thinlto.o";
92609467b48Spatrick       std::error_code EC;
92709467b48Spatrick       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
92809467b48Spatrick       error(EC, "error opening the file '" + OutputName + "'");
92909467b48Spatrick       OS << Binaries[BufID]->getBuffer();
93009467b48Spatrick     }
93109467b48Spatrick   }
93209467b48Spatrick 
93309467b48Spatrick   /// Load the combined index from disk, then load every file referenced by
93409467b48Spatrick };
93509467b48Spatrick 
93609467b48Spatrick } // end namespace thinlto
93709467b48Spatrick 
main(int argc,char ** argv)93809467b48Spatrick int main(int argc, char **argv) {
93909467b48Spatrick   InitLLVM X(argc, argv);
94073471bf0Spatrick   cl::HideUnrelatedOptions({&LTOCategory, &getColorCategory()});
94109467b48Spatrick   cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
94209467b48Spatrick 
94309467b48Spatrick   if (OptLevel < '0' || OptLevel > '3')
94409467b48Spatrick     error("optimization level must be between 0 and 3");
94509467b48Spatrick 
94609467b48Spatrick   // Initialize the configured targets.
94709467b48Spatrick   InitializeAllTargets();
94809467b48Spatrick   InitializeAllTargetMCs();
94909467b48Spatrick   InitializeAllAsmPrinters();
95009467b48Spatrick   InitializeAllAsmParsers();
95109467b48Spatrick 
95209467b48Spatrick   // set up the TargetOptions for the machine
95373471bf0Spatrick   TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
95409467b48Spatrick 
955*d415bd75Srobert   if (ListSymbolsOnly || QueryHasCtorDtor) {
956*d415bd75Srobert     testLTOModule(Options);
95709467b48Spatrick     return 0;
95809467b48Spatrick   }
95909467b48Spatrick 
96009467b48Spatrick   if (ListDependentLibrariesOnly) {
96109467b48Spatrick     listDependentLibraries();
96209467b48Spatrick     return 0;
96309467b48Spatrick   }
96409467b48Spatrick 
96509467b48Spatrick   if (IndexStats) {
96609467b48Spatrick     printIndexStats();
96709467b48Spatrick     return 0;
96809467b48Spatrick   }
96909467b48Spatrick 
97009467b48Spatrick   if (CheckHasObjC) {
97109467b48Spatrick     for (auto &Filename : InputFilenames) {
97209467b48Spatrick       ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +
97309467b48Spatrick                             Filename + "': ");
97409467b48Spatrick       std::unique_ptr<MemoryBuffer> BufferOrErr =
97509467b48Spatrick           ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(Filename)));
97609467b48Spatrick       auto Buffer = std::move(BufferOrErr.get());
97709467b48Spatrick       if (ExitOnErr(isBitcodeContainingObjCCategory(*Buffer)))
97809467b48Spatrick         outs() << "Bitcode " << Filename << " contains ObjC\n";
97909467b48Spatrick       else
98009467b48Spatrick         outs() << "Bitcode " << Filename << " does not contain ObjC\n";
98109467b48Spatrick     }
98209467b48Spatrick     return 0;
98309467b48Spatrick   }
98409467b48Spatrick 
985097a140dSpatrick   if (PrintMachOCPUOnly) {
986097a140dSpatrick     printMachOCPUOnly();
987097a140dSpatrick     return 0;
988097a140dSpatrick   }
989097a140dSpatrick 
99009467b48Spatrick   if (ThinLTOMode.getNumOccurrences()) {
99109467b48Spatrick     if (ThinLTOMode.getNumOccurrences() > 1)
99209467b48Spatrick       report_fatal_error("You can't specify more than one -thinlto-action");
99309467b48Spatrick     thinlto::ThinLTOProcessing ThinLTOProcessor(Options);
99409467b48Spatrick     ThinLTOProcessor.run();
99509467b48Spatrick     return 0;
99609467b48Spatrick   }
99709467b48Spatrick 
99809467b48Spatrick   if (ThinLTO) {
99909467b48Spatrick     createCombinedModuleSummaryIndex();
100009467b48Spatrick     return 0;
100109467b48Spatrick   }
100209467b48Spatrick 
100309467b48Spatrick   unsigned BaseArg = 0;
100409467b48Spatrick 
100509467b48Spatrick   LLVMContext Context;
100609467b48Spatrick   Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
100709467b48Spatrick                                true);
100809467b48Spatrick 
100909467b48Spatrick   LTOCodeGenerator CodeGen(Context);
101073471bf0Spatrick   CodeGen.setDisableVerify(DisableVerify);
101109467b48Spatrick 
101209467b48Spatrick   if (UseDiagnosticHandler)
101309467b48Spatrick     CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
101409467b48Spatrick 
1015097a140dSpatrick   CodeGen.setCodePICModel(codegen::getExplicitRelocModel());
101609467b48Spatrick   CodeGen.setFreestanding(EnableFreestanding);
1017*d415bd75Srobert   CodeGen.setDebugPassManager(DebugPassManager);
101809467b48Spatrick 
101909467b48Spatrick   CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
102009467b48Spatrick   CodeGen.setTargetOptions(Options);
102109467b48Spatrick   CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
102209467b48Spatrick 
102309467b48Spatrick   StringSet<MallocAllocator> DSOSymbolsSet;
102409467b48Spatrick   for (unsigned i = 0; i < DSOSymbols.size(); ++i)
102509467b48Spatrick     DSOSymbolsSet.insert(DSOSymbols[i]);
102609467b48Spatrick 
102709467b48Spatrick   std::vector<std::string> KeptDSOSyms;
102809467b48Spatrick 
102909467b48Spatrick   for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
103009467b48Spatrick     CurrentActivity = "loading file '" + InputFilenames[i] + "'";
103109467b48Spatrick     ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
103209467b48Spatrick         LTOModule::createFromFile(Context, InputFilenames[i], Options);
103309467b48Spatrick     std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
103409467b48Spatrick     CurrentActivity = "";
103509467b48Spatrick 
103609467b48Spatrick     unsigned NumSyms = Module->getSymbolCount();
103709467b48Spatrick     for (unsigned I = 0; I < NumSyms; ++I) {
103809467b48Spatrick       StringRef Name = Module->getSymbolName(I);
103909467b48Spatrick       if (!DSOSymbolsSet.count(Name))
104009467b48Spatrick         continue;
104109467b48Spatrick       lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
104209467b48Spatrick       unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
104309467b48Spatrick       if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
1044097a140dSpatrick         KeptDSOSyms.push_back(std::string(Name));
104509467b48Spatrick     }
104609467b48Spatrick 
104709467b48Spatrick     // We use the first input module as the destination module when
104809467b48Spatrick     // SetMergedModule is true.
104909467b48Spatrick     if (SetMergedModule && i == BaseArg) {
105009467b48Spatrick       // Transfer ownership to the code generator.
105109467b48Spatrick       CodeGen.setModule(std::move(Module));
105209467b48Spatrick     } else if (!CodeGen.addModule(Module.get())) {
105309467b48Spatrick       // Print a message here so that we know addModule() did not abort.
105409467b48Spatrick       error("error adding file '" + InputFilenames[i] + "'");
105509467b48Spatrick     }
105609467b48Spatrick   }
105709467b48Spatrick 
105809467b48Spatrick   // Add all the exported symbols to the table of symbols to preserve.
105909467b48Spatrick   for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
106009467b48Spatrick     CodeGen.addMustPreserveSymbol(ExportedSymbols[i]);
106109467b48Spatrick 
106209467b48Spatrick   // Add all the dso symbols to the table of symbols to expose.
106309467b48Spatrick   for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
106409467b48Spatrick     CodeGen.addMustPreserveSymbol(KeptDSOSyms[i]);
106509467b48Spatrick 
106609467b48Spatrick   // Set cpu and attrs strings for the default target/subtarget.
1067*d415bd75Srobert   CodeGen.setCpu(codegen::getMCPU());
106809467b48Spatrick 
106909467b48Spatrick   CodeGen.setOptLevel(OptLevel - '0');
107073471bf0Spatrick   CodeGen.setAttrs(codegen::getMAttrs());
107109467b48Spatrick 
1072097a140dSpatrick   if (auto FT = codegen::getExplicitFileType())
1073*d415bd75Srobert     CodeGen.setFileType(*FT);
107409467b48Spatrick 
107509467b48Spatrick   if (!OutputFilename.empty()) {
1076*d415bd75Srobert     if (LTOSaveBeforeOpt)
1077*d415bd75Srobert       CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");
1078*d415bd75Srobert 
107973471bf0Spatrick     if (SaveLinkedModuleFile) {
108073471bf0Spatrick       std::string ModuleFilename = OutputFilename;
108173471bf0Spatrick       ModuleFilename += ".linked.bc";
108273471bf0Spatrick       std::string ErrMsg;
108373471bf0Spatrick 
108473471bf0Spatrick       if (!CodeGen.writeMergedModules(ModuleFilename))
108573471bf0Spatrick         error("writing linked module failed.");
108673471bf0Spatrick     }
108773471bf0Spatrick 
108873471bf0Spatrick     if (!CodeGen.optimize()) {
108909467b48Spatrick       // Diagnostic messages should have been printed by the handler.
109009467b48Spatrick       error("error optimizing the code");
109109467b48Spatrick     }
109209467b48Spatrick 
109309467b48Spatrick     if (SaveModuleFile) {
109409467b48Spatrick       std::string ModuleFilename = OutputFilename;
109509467b48Spatrick       ModuleFilename += ".merged.bc";
109609467b48Spatrick       std::string ErrMsg;
109709467b48Spatrick 
109809467b48Spatrick       if (!CodeGen.writeMergedModules(ModuleFilename))
109909467b48Spatrick         error("writing merged module failed.");
110009467b48Spatrick     }
110109467b48Spatrick 
110273471bf0Spatrick     auto AddStream =
1103*d415bd75Srobert         [&](size_t Task,
1104*d415bd75Srobert             const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
110509467b48Spatrick       std::string PartFilename = OutputFilename;
110609467b48Spatrick       if (Parallelism != 1)
110773471bf0Spatrick         PartFilename += "." + utostr(Task);
110873471bf0Spatrick 
110909467b48Spatrick       std::error_code EC;
111073471bf0Spatrick       auto S =
111173471bf0Spatrick           std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);
111209467b48Spatrick       if (EC)
111309467b48Spatrick         error("error opening the file '" + PartFilename + "': " + EC.message());
1114*d415bd75Srobert       return std::make_unique<CachedFileStream>(std::move(S));
111573471bf0Spatrick     };
111609467b48Spatrick 
111773471bf0Spatrick     if (!CodeGen.compileOptimized(AddStream, Parallelism))
111809467b48Spatrick       // Diagnostic messages should have been printed by the handler.
111909467b48Spatrick       error("error compiling the code");
112009467b48Spatrick 
112109467b48Spatrick   } else {
112209467b48Spatrick     if (Parallelism != 1)
112309467b48Spatrick       error("-j must be specified together with -o");
112409467b48Spatrick 
112509467b48Spatrick     if (SaveModuleFile)
112609467b48Spatrick       error(": -save-merged-module must be specified with -o");
112709467b48Spatrick 
112809467b48Spatrick     const char *OutputName = nullptr;
112973471bf0Spatrick     if (!CodeGen.compile_to_file(&OutputName))
113009467b48Spatrick       error("error compiling the code");
113109467b48Spatrick       // Diagnostic messages should have been printed by the handler.
113209467b48Spatrick 
113309467b48Spatrick     outs() << "Wrote native object file '" << OutputName << "'\n";
113409467b48Spatrick   }
113509467b48Spatrick 
113609467b48Spatrick   return 0;
113709467b48Spatrick }
1138