109467b48Spatrick //===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
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 and performs
1009467b48Spatrick // link-time optimization according to the provided symbol resolutions using the
1109467b48Spatrick // resolution-based LTO interface, and outputs one or more object files.
1209467b48Spatrick //
1309467b48Spatrick // This program is intended to eventually replace llvm-lto which uses the legacy
1409467b48Spatrick // LTO interface.
1509467b48Spatrick //
1609467b48Spatrick //===----------------------------------------------------------------------===//
1709467b48Spatrick 
1809467b48Spatrick #include "llvm/Bitcode/BitcodeReader.h"
19097a140dSpatrick #include "llvm/CodeGen/CommandFlags.h"
2009467b48Spatrick #include "llvm/IR/DiagnosticPrinter.h"
2109467b48Spatrick #include "llvm/LTO/LTO.h"
22097a140dSpatrick #include "llvm/Passes/PassPlugin.h"
2373471bf0Spatrick #include "llvm/Remarks/HotnessThresholdParser.h"
24*d415bd75Srobert #include "llvm/Support/Caching.h"
2509467b48Spatrick #include "llvm/Support/CommandLine.h"
2609467b48Spatrick #include "llvm/Support/FileSystem.h"
2709467b48Spatrick #include "llvm/Support/InitLLVM.h"
28097a140dSpatrick #include "llvm/Support/PluginLoader.h"
2909467b48Spatrick #include "llvm/Support/TargetSelect.h"
3009467b48Spatrick #include "llvm/Support/Threading.h"
31*d415bd75Srobert #include <atomic>
3209467b48Spatrick 
3309467b48Spatrick using namespace llvm;
3409467b48Spatrick using namespace lto;
3509467b48Spatrick 
36097a140dSpatrick static codegen::RegisterCodeGenFlags CGF;
37097a140dSpatrick 
3809467b48Spatrick static cl::opt<char>
39*d415bd75Srobert     OptLevel("O",
40*d415bd75Srobert              cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
4109467b48Spatrick                       "(default = '-O2')"),
42*d415bd75Srobert              cl::Prefix, cl::init('2'));
4309467b48Spatrick 
4409467b48Spatrick static cl::opt<char> CGOptLevel(
4509467b48Spatrick     "cg-opt-level",
4609467b48Spatrick     cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"),
4709467b48Spatrick     cl::init('2'));
4809467b48Spatrick 
4909467b48Spatrick static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
5009467b48Spatrick                                             cl::desc("<input bitcode files>"));
5109467b48Spatrick 
5209467b48Spatrick static cl::opt<std::string> OutputFilename("o", cl::Required,
5309467b48Spatrick                                            cl::desc("Output filename"),
5409467b48Spatrick                                            cl::value_desc("filename"));
5509467b48Spatrick 
5609467b48Spatrick static cl::opt<std::string> CacheDir("cache-dir", cl::desc("Cache Directory"),
5709467b48Spatrick                                      cl::value_desc("directory"));
5809467b48Spatrick 
5909467b48Spatrick static cl::opt<std::string> OptPipeline("opt-pipeline",
6009467b48Spatrick                                         cl::desc("Optimizer Pipeline"),
6109467b48Spatrick                                         cl::value_desc("pipeline"));
6209467b48Spatrick 
6309467b48Spatrick static cl::opt<std::string> AAPipeline("aa-pipeline",
6409467b48Spatrick                                        cl::desc("Alias Analysis Pipeline"),
6509467b48Spatrick                                        cl::value_desc("aapipeline"));
6609467b48Spatrick 
6709467b48Spatrick static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
6809467b48Spatrick 
69*d415bd75Srobert static cl::list<std::string> SelectSaveTemps(
70*d415bd75Srobert     "select-save-temps",
71*d415bd75Srobert     cl::value_desc("One, or multiple of: "
72*d415bd75Srobert                    "resolution,preopt,promote,internalize,import,opt,precodegen"
73*d415bd75Srobert                    ",combinedindex"),
74*d415bd75Srobert     cl::desc("Save selected temporary files. Cannot be specified together with "
75*d415bd75Srobert              "-save-temps"),
76*d415bd75Srobert     cl::CommaSeparated);
77*d415bd75Srobert 
78*d415bd75Srobert constexpr const char *SaveTempsValues[] = {
79*d415bd75Srobert     "resolution", "preopt", "promote",    "internalize",
80*d415bd75Srobert     "import",     "opt",    "precodegen", "combinedindex"};
81*d415bd75Srobert 
8209467b48Spatrick static cl::opt<bool>
83*d415bd75Srobert     ThinLTODistributedIndexes("thinlto-distributed-indexes",
8409467b48Spatrick                               cl::desc("Write out individual index and "
8509467b48Spatrick                                        "import files for the "
8609467b48Spatrick                                        "distributed backend case"));
8709467b48Spatrick 
88*d415bd75Srobert static cl::opt<bool>
89*d415bd75Srobert     ThinLTOEmitIndexes("thinlto-emit-indexes",
90*d415bd75Srobert                        cl::desc("Write out individual index files via "
91*d415bd75Srobert                                 "InProcessThinLTO"));
92*d415bd75Srobert 
93*d415bd75Srobert static cl::opt<bool>
94*d415bd75Srobert     ThinLTOEmitImports("thinlto-emit-imports",
95*d415bd75Srobert                        cl::desc("Write out individual imports files via "
96*d415bd75Srobert                                 "InProcessThinLTO. Has no effect unless "
97*d415bd75Srobert                                 "specified with -thinlto-emit-indexes or "
98*d415bd75Srobert                                 "-thinlto-distributed-indexes"));
99*d415bd75Srobert 
100097a140dSpatrick // Default to using all available threads in the system, but using only one
101097a140dSpatrick // thread per core (no SMT).
102097a140dSpatrick // Use -thinlto-threads=all to use hardware_concurrency() instead, which means
103097a140dSpatrick // to use all hardware threads or cores in the system.
104097a140dSpatrick static cl::opt<std::string> Threads("thinlto-threads");
10509467b48Spatrick 
10609467b48Spatrick static cl::list<std::string> SymbolResolutions(
10709467b48Spatrick     "r",
10809467b48Spatrick     cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
10909467b48Spatrick              "where \"resolution\" is a sequence (which may be empty) of the\n"
11009467b48Spatrick              "following characters:\n"
11109467b48Spatrick              " p - prevailing: the linker has chosen this definition of the\n"
11209467b48Spatrick              "     symbol\n"
11309467b48Spatrick              " l - local: the definition of this symbol is unpreemptable at\n"
11409467b48Spatrick              "     runtime and is known to be in this linkage unit\n"
11509467b48Spatrick              " x - externally visible: the definition of this symbol is\n"
11609467b48Spatrick              "     visible outside of the LTO unit\n"
117*d415bd75Srobert              "A resolution for each symbol must be specified"));
11809467b48Spatrick 
11909467b48Spatrick static cl::opt<std::string> OverrideTriple(
12009467b48Spatrick     "override-triple",
12109467b48Spatrick     cl::desc("Replace target triples in input files with this triple"));
12209467b48Spatrick 
12309467b48Spatrick static cl::opt<std::string> DefaultTriple(
12409467b48Spatrick     "default-triple",
12509467b48Spatrick     cl::desc(
12609467b48Spatrick         "Replace unspecified target triples in input files with this triple"));
12709467b48Spatrick 
12809467b48Spatrick static cl::opt<bool> RemarksWithHotness(
12909467b48Spatrick     "pass-remarks-with-hotness",
13009467b48Spatrick     cl::desc("With PGO, include profile count in optimization remarks"),
13109467b48Spatrick     cl::Hidden);
13209467b48Spatrick 
133*d415bd75Srobert cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
13473471bf0Spatrick     RemarksHotnessThreshold(
13573471bf0Spatrick         "pass-remarks-hotness-threshold",
13673471bf0Spatrick         cl::desc("Minimum profile count required for an "
13773471bf0Spatrick                  "optimization remark to be output."
13873471bf0Spatrick                  " Use 'auto' to apply the threshold from profile summary."),
13973471bf0Spatrick         cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden);
14073471bf0Spatrick 
14109467b48Spatrick static cl::opt<std::string>
14209467b48Spatrick     RemarksFilename("pass-remarks-output",
14309467b48Spatrick                     cl::desc("Output filename for pass remarks"),
14409467b48Spatrick                     cl::value_desc("filename"));
14509467b48Spatrick 
14609467b48Spatrick static cl::opt<std::string>
14709467b48Spatrick     RemarksPasses("pass-remarks-filter",
14809467b48Spatrick                   cl::desc("Only record optimization remarks from passes whose "
14909467b48Spatrick                            "names match the given regular expression"),
15009467b48Spatrick                   cl::value_desc("regex"));
15109467b48Spatrick 
15209467b48Spatrick static cl::opt<std::string> RemarksFormat(
15309467b48Spatrick     "pass-remarks-format",
15409467b48Spatrick     cl::desc("The format used for serializing remarks (default: YAML)"),
15509467b48Spatrick     cl::value_desc("format"), cl::init("yaml"));
15609467b48Spatrick 
15709467b48Spatrick static cl::opt<std::string>
15809467b48Spatrick     SamplePGOFile("lto-sample-profile-file",
15909467b48Spatrick                   cl::desc("Specify a SamplePGO profile file"));
16009467b48Spatrick 
16109467b48Spatrick static cl::opt<std::string>
16209467b48Spatrick     CSPGOFile("lto-cspgo-profile-file",
16309467b48Spatrick               cl::desc("Specify a context sensitive PGO profile file"));
16409467b48Spatrick 
16509467b48Spatrick static cl::opt<bool>
16609467b48Spatrick     RunCSIRInstr("lto-cspgo-gen",
16709467b48Spatrick                  cl::desc("Run PGO context sensitive IR instrumentation"),
168*d415bd75Srobert                  cl::Hidden);
169*d415bd75Srobert 
170*d415bd75Srobert static cl::opt<bool> LtoOpaquePointers("lto-opaque-pointers",
171*d415bd75Srobert                                        cl::desc("Enable opaque pointer types"),
172*d415bd75Srobert                                        cl::init(true), cl::Hidden);
17309467b48Spatrick 
17409467b48Spatrick static cl::opt<bool>
175*d415bd75Srobert     DebugPassManager("debug-pass-manager", cl::Hidden,
17609467b48Spatrick                      cl::desc("Print pass management debugging information"));
17709467b48Spatrick 
17809467b48Spatrick static cl::opt<std::string>
17909467b48Spatrick     StatsFile("stats-file", cl::desc("Filename to write statistics to"));
18009467b48Spatrick 
181097a140dSpatrick static cl::list<std::string>
182097a140dSpatrick     PassPlugins("load-pass-plugin",
183097a140dSpatrick                 cl::desc("Load passes from plugin library"));
184097a140dSpatrick 
18573471bf0Spatrick static cl::opt<bool> EnableFreestanding(
18673471bf0Spatrick     "lto-freestanding",
18773471bf0Spatrick     cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
188*d415bd75Srobert     cl::Hidden);
18973471bf0Spatrick 
check(Error E,std::string Msg)19009467b48Spatrick static void check(Error E, std::string Msg) {
19109467b48Spatrick   if (!E)
19209467b48Spatrick     return;
19309467b48Spatrick   handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
19409467b48Spatrick     errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';
19509467b48Spatrick   });
19609467b48Spatrick   exit(1);
19709467b48Spatrick }
19809467b48Spatrick 
check(Expected<T> E,std::string Msg)19909467b48Spatrick template <typename T> static T check(Expected<T> E, std::string Msg) {
20009467b48Spatrick   if (E)
20109467b48Spatrick     return std::move(*E);
20209467b48Spatrick   check(E.takeError(), Msg);
20309467b48Spatrick   return T();
20409467b48Spatrick }
20509467b48Spatrick 
check(std::error_code EC,std::string Msg)20609467b48Spatrick static void check(std::error_code EC, std::string Msg) {
20709467b48Spatrick   check(errorCodeToError(EC), Msg);
20809467b48Spatrick }
20909467b48Spatrick 
check(ErrorOr<T> E,std::string Msg)21009467b48Spatrick template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
21109467b48Spatrick   if (E)
21209467b48Spatrick     return std::move(*E);
21309467b48Spatrick   check(E.getError(), Msg);
21409467b48Spatrick   return T();
21509467b48Spatrick }
21609467b48Spatrick 
usage()21709467b48Spatrick static int usage() {
21809467b48Spatrick   errs() << "Available subcommands: dump-symtab run\n";
21909467b48Spatrick   return 1;
22009467b48Spatrick }
22109467b48Spatrick 
run(int argc,char ** argv)22209467b48Spatrick static int run(int argc, char **argv) {
22309467b48Spatrick   cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
22409467b48Spatrick 
22509467b48Spatrick   // FIXME: Workaround PR30396 which means that a symbol can appear
22609467b48Spatrick   // more than once if it is defined in module-level assembly and
22709467b48Spatrick   // has a GV declaration. We allow (file, symbol) pairs to have multiple
22809467b48Spatrick   // resolutions and apply them in the order observed.
22909467b48Spatrick   std::map<std::pair<std::string, std::string>, std::list<SymbolResolution>>
23009467b48Spatrick       CommandLineResolutions;
23109467b48Spatrick   for (std::string R : SymbolResolutions) {
23209467b48Spatrick     StringRef Rest = R;
23309467b48Spatrick     StringRef FileName, SymbolName;
23409467b48Spatrick     std::tie(FileName, Rest) = Rest.split(',');
23509467b48Spatrick     if (Rest.empty()) {
23609467b48Spatrick       llvm::errs() << "invalid resolution: " << R << '\n';
23709467b48Spatrick       return 1;
23809467b48Spatrick     }
23909467b48Spatrick     std::tie(SymbolName, Rest) = Rest.split(',');
24009467b48Spatrick     SymbolResolution Res;
24109467b48Spatrick     for (char C : Rest) {
24209467b48Spatrick       if (C == 'p')
24309467b48Spatrick         Res.Prevailing = true;
24409467b48Spatrick       else if (C == 'l')
24509467b48Spatrick         Res.FinalDefinitionInLinkageUnit = true;
24609467b48Spatrick       else if (C == 'x')
24709467b48Spatrick         Res.VisibleToRegularObj = true;
24809467b48Spatrick       else if (C == 'r')
24909467b48Spatrick         Res.LinkerRedefined = true;
25009467b48Spatrick       else {
25109467b48Spatrick         llvm::errs() << "invalid character " << C << " in resolution: " << R
25209467b48Spatrick                      << '\n';
25309467b48Spatrick         return 1;
25409467b48Spatrick       }
25509467b48Spatrick     }
256097a140dSpatrick     CommandLineResolutions[{std::string(FileName), std::string(SymbolName)}]
257097a140dSpatrick         .push_back(Res);
25809467b48Spatrick   }
25909467b48Spatrick 
26009467b48Spatrick   std::vector<std::unique_ptr<MemoryBuffer>> MBs;
26109467b48Spatrick 
26209467b48Spatrick   Config Conf;
26309467b48Spatrick 
264097a140dSpatrick   Conf.CPU = codegen::getMCPU();
26573471bf0Spatrick   Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
266097a140dSpatrick   Conf.MAttrs = codegen::getMAttrs();
267097a140dSpatrick   if (auto RM = codegen::getExplicitRelocModel())
268*d415bd75Srobert     Conf.RelocModel = *RM;
269097a140dSpatrick   Conf.CodeModel = codegen::getExplicitCodeModel();
27009467b48Spatrick 
27109467b48Spatrick   Conf.DebugPassManager = DebugPassManager;
27209467b48Spatrick 
273*d415bd75Srobert   if (SaveTemps && !SelectSaveTemps.empty()) {
274*d415bd75Srobert     llvm::errs() << "-save-temps cannot be specified with -select-save-temps\n";
275*d415bd75Srobert     return 1;
276*d415bd75Srobert   }
277*d415bd75Srobert   if (SaveTemps || !SelectSaveTemps.empty()) {
278*d415bd75Srobert     DenseSet<StringRef> SaveTempsArgs;
279*d415bd75Srobert     for (auto &S : SelectSaveTemps)
280*d415bd75Srobert       if (is_contained(SaveTempsValues, S))
281*d415bd75Srobert         SaveTempsArgs.insert(S);
282*d415bd75Srobert       else {
283*d415bd75Srobert         llvm::errs() << ("invalid -select-save-temps argument: " + S) << '\n';
284*d415bd75Srobert         return 1;
285*d415bd75Srobert       }
286*d415bd75Srobert     check(Conf.addSaveTemps(OutputFilename + ".", false, SaveTempsArgs),
28709467b48Spatrick           "Config::addSaveTemps failed");
288*d415bd75Srobert   }
28909467b48Spatrick 
29009467b48Spatrick   // Optimization remarks.
29109467b48Spatrick   Conf.RemarksFilename = RemarksFilename;
29209467b48Spatrick   Conf.RemarksPasses = RemarksPasses;
29309467b48Spatrick   Conf.RemarksWithHotness = RemarksWithHotness;
29473471bf0Spatrick   Conf.RemarksHotnessThreshold = RemarksHotnessThreshold;
29509467b48Spatrick   Conf.RemarksFormat = RemarksFormat;
29609467b48Spatrick 
29709467b48Spatrick   Conf.SampleProfile = SamplePGOFile;
29809467b48Spatrick   Conf.CSIRProfile = CSPGOFile;
29909467b48Spatrick   Conf.RunCSIRInstr = RunCSIRInstr;
30009467b48Spatrick 
30109467b48Spatrick   // Run a custom pipeline, if asked for.
30209467b48Spatrick   Conf.OptPipeline = OptPipeline;
30309467b48Spatrick   Conf.AAPipeline = AAPipeline;
30409467b48Spatrick 
30509467b48Spatrick   Conf.OptLevel = OptLevel - '0';
30673471bf0Spatrick   Conf.Freestanding = EnableFreestanding;
307097a140dSpatrick   for (auto &PluginFN : PassPlugins)
308097a140dSpatrick     Conf.PassPlugins.push_back(PluginFN);
309*d415bd75Srobert   if (auto Level = CodeGenOpt::parseLevel(CGOptLevel)) {
310*d415bd75Srobert     Conf.CGOptLevel = *Level;
311*d415bd75Srobert   } else {
31209467b48Spatrick     llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n';
31309467b48Spatrick     return 1;
31409467b48Spatrick   }
31509467b48Spatrick 
316097a140dSpatrick   if (auto FT = codegen::getExplicitFileType())
317*d415bd75Srobert     Conf.CGFileType = *FT;
31809467b48Spatrick 
31909467b48Spatrick   Conf.OverrideTriple = OverrideTriple;
32009467b48Spatrick   Conf.DefaultTriple = DefaultTriple;
32109467b48Spatrick   Conf.StatsFile = StatsFile;
32209467b48Spatrick   Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
32309467b48Spatrick   Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
324*d415bd75Srobert   Conf.OpaquePointers = LtoOpaquePointers;
32509467b48Spatrick 
32609467b48Spatrick   ThinBackend Backend;
32709467b48Spatrick   if (ThinLTODistributedIndexes)
328*d415bd75Srobert     Backend =
329*d415bd75Srobert         createWriteIndexesThinBackend(/* OldPrefix */ "",
330*d415bd75Srobert                                       /* NewPrefix */ "", ThinLTOEmitImports,
33109467b48Spatrick                                       /* LinkedObjectsFile */ nullptr,
33209467b48Spatrick                                       /* OnWrite */ {});
33309467b48Spatrick   else
334097a140dSpatrick     Backend = createInProcessThinBackend(
335*d415bd75Srobert         llvm::heavyweight_hardware_concurrency(Threads),
336*d415bd75Srobert         /* OnWrite */ {}, ThinLTOEmitIndexes, ThinLTOEmitImports);
337*d415bd75Srobert 
338*d415bd75Srobert   // Track whether we hit an error; in particular, in the multi-threaded case,
339*d415bd75Srobert   // we can't exit() early because the rest of the threads wouldn't have had a
340*d415bd75Srobert   // change to be join-ed, and that would result in a "terminate called without
341*d415bd75Srobert   // an active exception". Altogether, this results in nondeterministic
342*d415bd75Srobert   // behavior. Instead, we don't exit in the multi-threaded case, but we make
343*d415bd75Srobert   // sure to report the error and then at the end (after joining cleanly)
344*d415bd75Srobert   // exit(1).
345*d415bd75Srobert   std::atomic<bool> HasErrors;
346*d415bd75Srobert   std::atomic_init(&HasErrors, false);
347*d415bd75Srobert   Conf.DiagHandler = [&](const DiagnosticInfo &DI) {
348*d415bd75Srobert     DiagnosticPrinterRawOStream DP(errs());
349*d415bd75Srobert     DI.print(DP);
350*d415bd75Srobert     errs() << '\n';
351*d415bd75Srobert     if (DI.getSeverity() == DS_Error)
352*d415bd75Srobert       HasErrors = true;
353*d415bd75Srobert   };
354*d415bd75Srobert 
35509467b48Spatrick   LTO Lto(std::move(Conf), std::move(Backend));
35609467b48Spatrick 
35709467b48Spatrick   for (std::string F : InputFilenames) {
35809467b48Spatrick     std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
35909467b48Spatrick     std::unique_ptr<InputFile> Input =
36009467b48Spatrick         check(InputFile::create(MB->getMemBufferRef()), F);
36109467b48Spatrick 
36209467b48Spatrick     std::vector<SymbolResolution> Res;
36309467b48Spatrick     for (const InputFile::Symbol &Sym : Input->symbols()) {
364097a140dSpatrick       auto I = CommandLineResolutions.find({F, std::string(Sym.getName())});
36573471bf0Spatrick       // If it isn't found, look for ".", which would have been added
36609467b48Spatrick       // (followed by a hash) when the symbol was promoted during module
36709467b48Spatrick       // splitting if it was defined in one part and used in the other.
36873471bf0Spatrick       // Try looking up the symbol name before the suffix.
36909467b48Spatrick       if (I == CommandLineResolutions.end()) {
37073471bf0Spatrick         auto SplitName = Sym.getName().rsplit(".");
371097a140dSpatrick         I = CommandLineResolutions.find({F, std::string(SplitName.first)});
37209467b48Spatrick       }
37309467b48Spatrick       if (I == CommandLineResolutions.end()) {
37409467b48Spatrick         llvm::errs() << argv[0] << ": missing symbol resolution for " << F
37509467b48Spatrick                      << ',' << Sym.getName() << '\n';
37609467b48Spatrick         HasErrors = true;
37709467b48Spatrick       } else {
37809467b48Spatrick         Res.push_back(I->second.front());
37909467b48Spatrick         I->second.pop_front();
38009467b48Spatrick         if (I->second.empty())
38109467b48Spatrick           CommandLineResolutions.erase(I);
38209467b48Spatrick       }
38309467b48Spatrick     }
38409467b48Spatrick 
38509467b48Spatrick     if (HasErrors)
38609467b48Spatrick       continue;
38709467b48Spatrick 
38809467b48Spatrick     MBs.push_back(std::move(MB));
38909467b48Spatrick     check(Lto.add(std::move(Input), Res), F);
39009467b48Spatrick   }
39109467b48Spatrick 
39209467b48Spatrick   if (!CommandLineResolutions.empty()) {
39309467b48Spatrick     HasErrors = true;
39409467b48Spatrick     for (auto UnusedRes : CommandLineResolutions)
39509467b48Spatrick       llvm::errs() << argv[0] << ": unused symbol resolution for "
39609467b48Spatrick                    << UnusedRes.first.first << ',' << UnusedRes.first.second
39709467b48Spatrick                    << '\n';
39809467b48Spatrick   }
39909467b48Spatrick   if (HasErrors)
40009467b48Spatrick     return 1;
40109467b48Spatrick 
40209467b48Spatrick   auto AddStream =
403*d415bd75Srobert       [&](size_t Task,
404*d415bd75Srobert           const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
40509467b48Spatrick     std::string Path = OutputFilename + "." + utostr(Task);
40609467b48Spatrick 
40709467b48Spatrick     std::error_code EC;
40809467b48Spatrick     auto S = std::make_unique<raw_fd_ostream>(Path, EC, sys::fs::OF_None);
40909467b48Spatrick     check(EC, Path);
410*d415bd75Srobert     return std::make_unique<CachedFileStream>(std::move(S), Path);
41109467b48Spatrick   };
41209467b48Spatrick 
413*d415bd75Srobert   auto AddBuffer = [&](size_t Task, const Twine &ModuleName,
414*d415bd75Srobert                        std::unique_ptr<MemoryBuffer> MB) {
415*d415bd75Srobert     *AddStream(Task, ModuleName)->OS << MB->getBuffer();
41609467b48Spatrick   };
41709467b48Spatrick 
418*d415bd75Srobert   FileCache Cache;
41909467b48Spatrick   if (!CacheDir.empty())
420*d415bd75Srobert     Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),
421*d415bd75Srobert                   "failed to create cache");
42209467b48Spatrick 
42309467b48Spatrick   check(Lto.run(AddStream, Cache), "LTO::run failed");
424*d415bd75Srobert   return static_cast<int>(HasErrors);
42509467b48Spatrick }
42609467b48Spatrick 
dumpSymtab(int argc,char ** argv)42709467b48Spatrick static int dumpSymtab(int argc, char **argv) {
42809467b48Spatrick   for (StringRef F : make_range(argv + 1, argv + argc)) {
429097a140dSpatrick     std::unique_ptr<MemoryBuffer> MB =
430097a140dSpatrick         check(MemoryBuffer::getFile(F), std::string(F));
431097a140dSpatrick     BitcodeFileContents BFC =
432097a140dSpatrick         check(getBitcodeFileContents(*MB), std::string(F));
43309467b48Spatrick 
43409467b48Spatrick     if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) {
43509467b48Spatrick       auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>(
43609467b48Spatrick           BFC.Symtab.data());
43709467b48Spatrick       outs() << "version: " << Hdr->Version << '\n';
43809467b48Spatrick       if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion)
43909467b48Spatrick         outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab)
44009467b48Spatrick                << '\n';
44109467b48Spatrick     }
44209467b48Spatrick 
44309467b48Spatrick     std::unique_ptr<InputFile> Input =
444097a140dSpatrick         check(InputFile::create(MB->getMemBufferRef()), std::string(F));
44509467b48Spatrick 
44609467b48Spatrick     outs() << "target triple: " << Input->getTargetTriple() << '\n';
44709467b48Spatrick     Triple TT(Input->getTargetTriple());
44809467b48Spatrick 
44909467b48Spatrick     outs() << "source filename: " << Input->getSourceFileName() << '\n';
45009467b48Spatrick 
45109467b48Spatrick     if (TT.isOSBinFormatCOFF())
45209467b48Spatrick       outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
45309467b48Spatrick 
45409467b48Spatrick     if (TT.isOSBinFormatELF()) {
45509467b48Spatrick       outs() << "dependent libraries:";
45609467b48Spatrick       for (auto L : Input->getDependentLibraries())
45709467b48Spatrick         outs() << " \"" << L << "\"";
45809467b48Spatrick       outs() << '\n';
45909467b48Spatrick     }
46009467b48Spatrick 
46173471bf0Spatrick     ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable =
46273471bf0Spatrick         Input->getComdatTable();
46309467b48Spatrick     for (const InputFile::Symbol &Sym : Input->symbols()) {
46409467b48Spatrick       switch (Sym.getVisibility()) {
46509467b48Spatrick       case GlobalValue::HiddenVisibility:
46609467b48Spatrick         outs() << 'H';
46709467b48Spatrick         break;
46809467b48Spatrick       case GlobalValue::ProtectedVisibility:
46909467b48Spatrick         outs() << 'P';
47009467b48Spatrick         break;
47109467b48Spatrick       case GlobalValue::DefaultVisibility:
47209467b48Spatrick         outs() << 'D';
47309467b48Spatrick         break;
47409467b48Spatrick       }
47509467b48Spatrick 
47609467b48Spatrick       auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };
47709467b48Spatrick       PrintBool('U', Sym.isUndefined());
47809467b48Spatrick       PrintBool('C', Sym.isCommon());
47909467b48Spatrick       PrintBool('W', Sym.isWeak());
48009467b48Spatrick       PrintBool('I', Sym.isIndirect());
48109467b48Spatrick       PrintBool('O', Sym.canBeOmittedFromSymbolTable());
48209467b48Spatrick       PrintBool('T', Sym.isTLS());
48309467b48Spatrick       PrintBool('X', Sym.isExecutable());
48409467b48Spatrick       outs() << ' ' << Sym.getName() << '\n';
48509467b48Spatrick 
48609467b48Spatrick       if (Sym.isCommon())
48709467b48Spatrick         outs() << "         size " << Sym.getCommonSize() << " align "
48809467b48Spatrick                << Sym.getCommonAlignment() << '\n';
48909467b48Spatrick 
49009467b48Spatrick       int Comdat = Sym.getComdatIndex();
49173471bf0Spatrick       if (Comdat != -1) {
49273471bf0Spatrick         outs() << "         comdat ";
49373471bf0Spatrick         switch (ComdatTable[Comdat].second) {
49473471bf0Spatrick         case Comdat::Any:
49573471bf0Spatrick           outs() << "any";
49673471bf0Spatrick           break;
49773471bf0Spatrick         case Comdat::ExactMatch:
49873471bf0Spatrick           outs() << "exactmatch";
49973471bf0Spatrick           break;
50073471bf0Spatrick         case Comdat::Largest:
50173471bf0Spatrick           outs() << "largest";
50273471bf0Spatrick           break;
50373471bf0Spatrick         case Comdat::NoDeduplicate:
50473471bf0Spatrick           outs() << "nodeduplicate";
50573471bf0Spatrick           break;
50673471bf0Spatrick         case Comdat::SameSize:
50773471bf0Spatrick           outs() << "samesize";
50873471bf0Spatrick           break;
50973471bf0Spatrick         }
51073471bf0Spatrick         outs() << ' ' << ComdatTable[Comdat].first << '\n';
51173471bf0Spatrick       }
51209467b48Spatrick 
51309467b48Spatrick       if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
51409467b48Spatrick         outs() << "         fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
51509467b48Spatrick 
51609467b48Spatrick       if (!Sym.getSectionName().empty())
51709467b48Spatrick         outs() << "         section " << Sym.getSectionName() << "\n";
51809467b48Spatrick     }
51909467b48Spatrick 
52009467b48Spatrick     outs() << '\n';
52109467b48Spatrick   }
52209467b48Spatrick 
52309467b48Spatrick   return 0;
52409467b48Spatrick }
52509467b48Spatrick 
main(int argc,char ** argv)52609467b48Spatrick int main(int argc, char **argv) {
52709467b48Spatrick   InitLLVM X(argc, argv);
52809467b48Spatrick   InitializeAllTargets();
52909467b48Spatrick   InitializeAllTargetMCs();
53009467b48Spatrick   InitializeAllAsmPrinters();
53109467b48Spatrick   InitializeAllAsmParsers();
53209467b48Spatrick 
53309467b48Spatrick   // FIXME: This should use llvm::cl subcommands, but it isn't currently
53409467b48Spatrick   // possible to pass an argument not associated with a subcommand to a
53509467b48Spatrick   // subcommand (e.g. -use-new-pm).
53609467b48Spatrick   if (argc < 2)
53709467b48Spatrick     return usage();
53809467b48Spatrick 
53909467b48Spatrick   StringRef Subcommand = argv[1];
54009467b48Spatrick   // Ensure that argv[0] is correct after adjusting argv/argc.
54109467b48Spatrick   argv[1] = argv[0];
54209467b48Spatrick   if (Subcommand == "dump-symtab")
54309467b48Spatrick     return dumpSymtab(argc - 1, argv + 1);
54409467b48Spatrick   if (Subcommand == "run")
54509467b48Spatrick     return run(argc - 1, argv + 1);
54609467b48Spatrick   return usage();
54709467b48Spatrick }
548