xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This program takes in a list of bitcode files, links them and performs
100b57cec5SDimitry Andric // link-time optimization according to the provided symbol resolutions using the
110b57cec5SDimitry Andric // resolution-based LTO interface, and outputs one or more object files.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // This program is intended to eventually replace llvm-lto which uses the legacy
140b57cec5SDimitry Andric // LTO interface.
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeReader.h"
195ffd83dbSDimitry Andric #include "llvm/CodeGen/CommandFlags.h"
200b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h"
210b57cec5SDimitry Andric #include "llvm/LTO/LTO.h"
225ffd83dbSDimitry Andric #include "llvm/Passes/PassPlugin.h"
23e8d8bef9SDimitry Andric #include "llvm/Remarks/HotnessThresholdParser.h"
24349cc55cSDimitry Andric #include "llvm/Support/Caching.h"
250b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
260b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
270b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
285ffd83dbSDimitry Andric #include "llvm/Support/PluginLoader.h"
290b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
300b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
310eae32dcSDimitry Andric #include <atomic>
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric using namespace lto;
350b57cec5SDimitry Andric 
365ffd83dbSDimitry Andric static codegen::RegisterCodeGenFlags CGF;
375ffd83dbSDimitry Andric 
380b57cec5SDimitry Andric static cl::opt<char>
3981ad6265SDimitry Andric     OptLevel("O",
4081ad6265SDimitry Andric              cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
410b57cec5SDimitry Andric                       "(default = '-O2')"),
4281ad6265SDimitry Andric              cl::Prefix, cl::init('2'));
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric static cl::opt<char> CGOptLevel(
450b57cec5SDimitry Andric     "cg-opt-level",
460b57cec5SDimitry Andric     cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"),
470b57cec5SDimitry Andric     cl::init('2'));
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
500b57cec5SDimitry Andric                                             cl::desc("<input bitcode files>"));
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric static cl::opt<std::string> OutputFilename("o", cl::Required,
530b57cec5SDimitry Andric                                            cl::desc("Output filename"),
540b57cec5SDimitry Andric                                            cl::value_desc("filename"));
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric static cl::opt<std::string> CacheDir("cache-dir", cl::desc("Cache Directory"),
570b57cec5SDimitry Andric                                      cl::value_desc("directory"));
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric static cl::opt<std::string> OptPipeline("opt-pipeline",
600b57cec5SDimitry Andric                                         cl::desc("Optimizer Pipeline"),
610b57cec5SDimitry Andric                                         cl::value_desc("pipeline"));
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric static cl::opt<std::string> AAPipeline("aa-pipeline",
640b57cec5SDimitry Andric                                        cl::desc("Alias Analysis Pipeline"),
650b57cec5SDimitry Andric                                        cl::value_desc("aapipeline"));
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
680b57cec5SDimitry Andric 
69753f127fSDimitry Andric static cl::list<std::string> SelectSaveTemps(
70753f127fSDimitry Andric     "select-save-temps",
71753f127fSDimitry Andric     cl::value_desc("One, or multiple of: "
72753f127fSDimitry Andric                    "resolution,preopt,promote,internalize,import,opt,precodegen"
73753f127fSDimitry Andric                    ",combinedindex"),
74753f127fSDimitry Andric     cl::desc("Save selected temporary files. Cannot be specified together with "
75753f127fSDimitry Andric              "-save-temps"),
76753f127fSDimitry Andric     cl::CommaSeparated);
77753f127fSDimitry Andric 
78753f127fSDimitry Andric constexpr const char *SaveTempsValues[] = {
79753f127fSDimitry Andric     "resolution", "preopt", "promote",    "internalize",
80753f127fSDimitry Andric     "import",     "opt",    "precodegen", "combinedindex"};
81753f127fSDimitry Andric 
820b57cec5SDimitry Andric static cl::opt<bool>
8381ad6265SDimitry Andric     ThinLTODistributedIndexes("thinlto-distributed-indexes",
840b57cec5SDimitry Andric                               cl::desc("Write out individual index and "
850b57cec5SDimitry Andric                                        "import files for the "
860b57cec5SDimitry Andric                                        "distributed backend case"));
870b57cec5SDimitry Andric 
8881ad6265SDimitry Andric static cl::opt<bool>
8981ad6265SDimitry Andric     ThinLTOEmitIndexes("thinlto-emit-indexes",
9081ad6265SDimitry Andric                        cl::desc("Write out individual index files via "
9181ad6265SDimitry Andric                                 "InProcessThinLTO"));
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric static cl::opt<bool>
9481ad6265SDimitry Andric     ThinLTOEmitImports("thinlto-emit-imports",
9581ad6265SDimitry Andric                        cl::desc("Write out individual imports files via "
9681ad6265SDimitry Andric                                 "InProcessThinLTO. Has no effect unless "
9781ad6265SDimitry Andric                                 "specified with -thinlto-emit-indexes or "
9881ad6265SDimitry Andric                                 "-thinlto-distributed-indexes"));
9981ad6265SDimitry Andric 
1005ffd83dbSDimitry Andric // Default to using all available threads in the system, but using only one
1015ffd83dbSDimitry Andric // thread per core (no SMT).
1025ffd83dbSDimitry Andric // Use -thinlto-threads=all to use hardware_concurrency() instead, which means
1035ffd83dbSDimitry Andric // to use all hardware threads or cores in the system.
1045ffd83dbSDimitry Andric static cl::opt<std::string> Threads("thinlto-threads");
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric static cl::list<std::string> SymbolResolutions(
1070b57cec5SDimitry Andric     "r",
1080b57cec5SDimitry Andric     cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
1090b57cec5SDimitry Andric              "where \"resolution\" is a sequence (which may be empty) of the\n"
1100b57cec5SDimitry Andric              "following characters:\n"
1110b57cec5SDimitry Andric              " p - prevailing: the linker has chosen this definition of the\n"
1120b57cec5SDimitry Andric              "     symbol\n"
1130b57cec5SDimitry Andric              " l - local: the definition of this symbol is unpreemptable at\n"
1140b57cec5SDimitry Andric              "     runtime and is known to be in this linkage unit\n"
1150b57cec5SDimitry Andric              " x - externally visible: the definition of this symbol is\n"
1160b57cec5SDimitry Andric              "     visible outside of the LTO unit\n"
11781ad6265SDimitry Andric              "A resolution for each symbol must be specified"));
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric static cl::opt<std::string> OverrideTriple(
1200b57cec5SDimitry Andric     "override-triple",
1210b57cec5SDimitry Andric     cl::desc("Replace target triples in input files with this triple"));
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric static cl::opt<std::string> DefaultTriple(
1240b57cec5SDimitry Andric     "default-triple",
1250b57cec5SDimitry Andric     cl::desc(
1260b57cec5SDimitry Andric         "Replace unspecified target triples in input files with this triple"));
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric static cl::opt<bool> RemarksWithHotness(
1290b57cec5SDimitry Andric     "pass-remarks-with-hotness",
1300b57cec5SDimitry Andric     cl::desc("With PGO, include profile count in optimization remarks"),
1310b57cec5SDimitry Andric     cl::Hidden);
1320b57cec5SDimitry Andric 
133bdd1243dSDimitry Andric cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
134e8d8bef9SDimitry Andric     RemarksHotnessThreshold(
135e8d8bef9SDimitry Andric         "pass-remarks-hotness-threshold",
136e8d8bef9SDimitry Andric         cl::desc("Minimum profile count required for an "
137e8d8bef9SDimitry Andric                  "optimization remark to be output."
138e8d8bef9SDimitry Andric                  " Use 'auto' to apply the threshold from profile summary."),
139e8d8bef9SDimitry Andric         cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden);
140e8d8bef9SDimitry Andric 
1410b57cec5SDimitry Andric static cl::opt<std::string>
1420b57cec5SDimitry Andric     RemarksFilename("pass-remarks-output",
1430b57cec5SDimitry Andric                     cl::desc("Output filename for pass remarks"),
1440b57cec5SDimitry Andric                     cl::value_desc("filename"));
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric static cl::opt<std::string>
1470b57cec5SDimitry Andric     RemarksPasses("pass-remarks-filter",
1480b57cec5SDimitry Andric                   cl::desc("Only record optimization remarks from passes whose "
1490b57cec5SDimitry Andric                            "names match the given regular expression"),
1500b57cec5SDimitry Andric                   cl::value_desc("regex"));
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric static cl::opt<std::string> RemarksFormat(
1530b57cec5SDimitry Andric     "pass-remarks-format",
1540b57cec5SDimitry Andric     cl::desc("The format used for serializing remarks (default: YAML)"),
1550b57cec5SDimitry Andric     cl::value_desc("format"), cl::init("yaml"));
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric static cl::opt<std::string>
1580b57cec5SDimitry Andric     SamplePGOFile("lto-sample-profile-file",
1590b57cec5SDimitry Andric                   cl::desc("Specify a SamplePGO profile file"));
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric static cl::opt<std::string>
1620b57cec5SDimitry Andric     CSPGOFile("lto-cspgo-profile-file",
1630b57cec5SDimitry Andric               cl::desc("Specify a context sensitive PGO profile file"));
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric static cl::opt<bool>
1660b57cec5SDimitry Andric     RunCSIRInstr("lto-cspgo-gen",
1670b57cec5SDimitry Andric                  cl::desc("Run PGO context sensitive IR instrumentation"),
16881ad6265SDimitry Andric                  cl::Hidden);
16981ad6265SDimitry Andric 
1700b57cec5SDimitry Andric static cl::opt<bool>
17181ad6265SDimitry Andric     DebugPassManager("debug-pass-manager", cl::Hidden,
1720b57cec5SDimitry Andric                      cl::desc("Print pass management debugging information"));
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric static cl::opt<std::string>
1750b57cec5SDimitry Andric     StatsFile("stats-file", cl::desc("Filename to write statistics to"));
1760b57cec5SDimitry Andric 
1775ffd83dbSDimitry Andric static cl::list<std::string>
1785ffd83dbSDimitry Andric     PassPlugins("load-pass-plugin",
1795ffd83dbSDimitry Andric                 cl::desc("Load passes from plugin library"));
1805ffd83dbSDimitry Andric 
18106c3fb27SDimitry Andric static cl::opt<std::string> UnifiedLTOMode("unified-lto", cl::Optional,
18206c3fb27SDimitry Andric                                            cl::desc("Set LTO mode"),
18306c3fb27SDimitry Andric                                            cl::value_desc("mode"));
18406c3fb27SDimitry Andric 
185e8d8bef9SDimitry Andric static cl::opt<bool> EnableFreestanding(
186e8d8bef9SDimitry Andric     "lto-freestanding",
187e8d8bef9SDimitry Andric     cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
18881ad6265SDimitry Andric     cl::Hidden);
189e8d8bef9SDimitry Andric 
190*0fca6ea1SDimitry Andric static cl::opt<bool> TryUseNewDbgInfoFormat(
191*0fca6ea1SDimitry Andric     "try-experimental-debuginfo-iterators",
192*0fca6ea1SDimitry Andric     cl::desc("Enable debuginfo iterator positions, if they're built in"),
193*0fca6ea1SDimitry Andric     cl::init(false), cl::Hidden);
194*0fca6ea1SDimitry Andric 
195*0fca6ea1SDimitry Andric extern cl::opt<bool> UseNewDbgInfoFormat;
196*0fca6ea1SDimitry Andric extern cl::opt<cl::boolOrDefault> LoadBitcodeIntoNewDbgInfoFormat;
197*0fca6ea1SDimitry Andric extern cl::opt<cl::boolOrDefault> PreserveInputDbgFormat;
198*0fca6ea1SDimitry Andric 
1990b57cec5SDimitry Andric static void check(Error E, std::string Msg) {
2000b57cec5SDimitry Andric   if (!E)
2010b57cec5SDimitry Andric     return;
2020b57cec5SDimitry Andric   handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
2030b57cec5SDimitry Andric     errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';
2040b57cec5SDimitry Andric   });
2050b57cec5SDimitry Andric   exit(1);
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric template <typename T> static T check(Expected<T> E, std::string Msg) {
2090b57cec5SDimitry Andric   if (E)
2100b57cec5SDimitry Andric     return std::move(*E);
2110b57cec5SDimitry Andric   check(E.takeError(), Msg);
2120b57cec5SDimitry Andric   return T();
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric static void check(std::error_code EC, std::string Msg) {
2160b57cec5SDimitry Andric   check(errorCodeToError(EC), Msg);
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
2200b57cec5SDimitry Andric   if (E)
2210b57cec5SDimitry Andric     return std::move(*E);
2220b57cec5SDimitry Andric   check(E.getError(), Msg);
2230b57cec5SDimitry Andric   return T();
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric static int usage() {
2270b57cec5SDimitry Andric   errs() << "Available subcommands: dump-symtab run\n";
2280b57cec5SDimitry Andric   return 1;
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric static int run(int argc, char **argv) {
2320b57cec5SDimitry Andric   cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
233*0fca6ea1SDimitry Andric   // Load bitcode into the new debug info format by default.
234*0fca6ea1SDimitry Andric   if (LoadBitcodeIntoNewDbgInfoFormat == cl::boolOrDefault::BOU_UNSET)
235*0fca6ea1SDimitry Andric     LoadBitcodeIntoNewDbgInfoFormat = cl::boolOrDefault::BOU_TRUE;
236*0fca6ea1SDimitry Andric 
237*0fca6ea1SDimitry Andric   // RemoveDIs debug-info transition: tests may request that we /try/ to use the
238*0fca6ea1SDimitry Andric   // new debug-info format.
239*0fca6ea1SDimitry Andric   if (TryUseNewDbgInfoFormat) {
240*0fca6ea1SDimitry Andric     // Turn the new debug-info format on.
241*0fca6ea1SDimitry Andric     UseNewDbgInfoFormat = true;
242*0fca6ea1SDimitry Andric   }
243*0fca6ea1SDimitry Andric   // Since llvm-lto2 collects multiple IR modules together, for simplicity's
244*0fca6ea1SDimitry Andric   // sake we disable the "PreserveInputDbgFormat" flag to enforce a single debug
245*0fca6ea1SDimitry Andric   // info format.
246*0fca6ea1SDimitry Andric   PreserveInputDbgFormat = cl::boolOrDefault::BOU_FALSE;
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   // FIXME: Workaround PR30396 which means that a symbol can appear
2490b57cec5SDimitry Andric   // more than once if it is defined in module-level assembly and
2500b57cec5SDimitry Andric   // has a GV declaration. We allow (file, symbol) pairs to have multiple
2510b57cec5SDimitry Andric   // resolutions and apply them in the order observed.
2520b57cec5SDimitry Andric   std::map<std::pair<std::string, std::string>, std::list<SymbolResolution>>
2530b57cec5SDimitry Andric       CommandLineResolutions;
254*0fca6ea1SDimitry Andric   for (StringRef R : SymbolResolutions) {
255*0fca6ea1SDimitry Andric     StringRef Rest, FileName, SymbolName;
256*0fca6ea1SDimitry Andric     std::tie(FileName, Rest) = R.split(',');
2570b57cec5SDimitry Andric     if (Rest.empty()) {
2580b57cec5SDimitry Andric       llvm::errs() << "invalid resolution: " << R << '\n';
2590b57cec5SDimitry Andric       return 1;
2600b57cec5SDimitry Andric     }
2610b57cec5SDimitry Andric     std::tie(SymbolName, Rest) = Rest.split(',');
2620b57cec5SDimitry Andric     SymbolResolution Res;
2630b57cec5SDimitry Andric     for (char C : Rest) {
2640b57cec5SDimitry Andric       if (C == 'p')
2650b57cec5SDimitry Andric         Res.Prevailing = true;
2660b57cec5SDimitry Andric       else if (C == 'l')
2670b57cec5SDimitry Andric         Res.FinalDefinitionInLinkageUnit = true;
2680b57cec5SDimitry Andric       else if (C == 'x')
2690b57cec5SDimitry Andric         Res.VisibleToRegularObj = true;
2700b57cec5SDimitry Andric       else if (C == 'r')
2710b57cec5SDimitry Andric         Res.LinkerRedefined = true;
2720b57cec5SDimitry Andric       else {
2730b57cec5SDimitry Andric         llvm::errs() << "invalid character " << C << " in resolution: " << R
2740b57cec5SDimitry Andric                      << '\n';
2750b57cec5SDimitry Andric         return 1;
2760b57cec5SDimitry Andric       }
2770b57cec5SDimitry Andric     }
2785ffd83dbSDimitry Andric     CommandLineResolutions[{std::string(FileName), std::string(SymbolName)}]
2795ffd83dbSDimitry Andric         .push_back(Res);
2800b57cec5SDimitry Andric   }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   std::vector<std::unique_ptr<MemoryBuffer>> MBs;
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   Config Conf;
2850b57cec5SDimitry Andric 
2865ffd83dbSDimitry Andric   Conf.CPU = codegen::getMCPU();
287e8d8bef9SDimitry Andric   Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
2885ffd83dbSDimitry Andric   Conf.MAttrs = codegen::getMAttrs();
2895ffd83dbSDimitry Andric   if (auto RM = codegen::getExplicitRelocModel())
29081ad6265SDimitry Andric     Conf.RelocModel = *RM;
2915ffd83dbSDimitry Andric   Conf.CodeModel = codegen::getExplicitCodeModel();
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   Conf.DebugPassManager = DebugPassManager;
2940b57cec5SDimitry Andric 
295753f127fSDimitry Andric   if (SaveTemps && !SelectSaveTemps.empty()) {
296753f127fSDimitry Andric     llvm::errs() << "-save-temps cannot be specified with -select-save-temps\n";
297753f127fSDimitry Andric     return 1;
298753f127fSDimitry Andric   }
299753f127fSDimitry Andric   if (SaveTemps || !SelectSaveTemps.empty()) {
300753f127fSDimitry Andric     DenseSet<StringRef> SaveTempsArgs;
301753f127fSDimitry Andric     for (auto &S : SelectSaveTemps)
302753f127fSDimitry Andric       if (is_contained(SaveTempsValues, S))
303753f127fSDimitry Andric         SaveTempsArgs.insert(S);
304753f127fSDimitry Andric       else {
305753f127fSDimitry Andric         llvm::errs() << ("invalid -select-save-temps argument: " + S) << '\n';
306753f127fSDimitry Andric         return 1;
307753f127fSDimitry Andric       }
308753f127fSDimitry Andric     check(Conf.addSaveTemps(OutputFilename + ".", false, SaveTempsArgs),
3090b57cec5SDimitry Andric           "Config::addSaveTemps failed");
310753f127fSDimitry Andric   }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   // Optimization remarks.
3130b57cec5SDimitry Andric   Conf.RemarksFilename = RemarksFilename;
3140b57cec5SDimitry Andric   Conf.RemarksPasses = RemarksPasses;
3150b57cec5SDimitry Andric   Conf.RemarksWithHotness = RemarksWithHotness;
316e8d8bef9SDimitry Andric   Conf.RemarksHotnessThreshold = RemarksHotnessThreshold;
3170b57cec5SDimitry Andric   Conf.RemarksFormat = RemarksFormat;
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   Conf.SampleProfile = SamplePGOFile;
3200b57cec5SDimitry Andric   Conf.CSIRProfile = CSPGOFile;
3210b57cec5SDimitry Andric   Conf.RunCSIRInstr = RunCSIRInstr;
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   // Run a custom pipeline, if asked for.
3240b57cec5SDimitry Andric   Conf.OptPipeline = OptPipeline;
3250b57cec5SDimitry Andric   Conf.AAPipeline = AAPipeline;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   Conf.OptLevel = OptLevel - '0';
328e8d8bef9SDimitry Andric   Conf.Freestanding = EnableFreestanding;
3295ffd83dbSDimitry Andric   for (auto &PluginFN : PassPlugins)
3305ffd83dbSDimitry Andric     Conf.PassPlugins.push_back(PluginFN);
331bdd1243dSDimitry Andric   if (auto Level = CodeGenOpt::parseLevel(CGOptLevel)) {
332bdd1243dSDimitry Andric     Conf.CGOptLevel = *Level;
333bdd1243dSDimitry Andric   } else {
3340b57cec5SDimitry Andric     llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n';
3350b57cec5SDimitry Andric     return 1;
3360b57cec5SDimitry Andric   }
3370b57cec5SDimitry Andric 
3385ffd83dbSDimitry Andric   if (auto FT = codegen::getExplicitFileType())
33981ad6265SDimitry Andric     Conf.CGFileType = *FT;
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   Conf.OverrideTriple = OverrideTriple;
3420b57cec5SDimitry Andric   Conf.DefaultTriple = DefaultTriple;
3430b57cec5SDimitry Andric   Conf.StatsFile = StatsFile;
344480093f4SDimitry Andric   Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
345480093f4SDimitry Andric   Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   ThinBackend Backend;
3480b57cec5SDimitry Andric   if (ThinLTODistributedIndexes)
34906c3fb27SDimitry Andric     Backend = createWriteIndexesThinBackend(/*OldPrefix=*/"",
35006c3fb27SDimitry Andric                                             /*NewPrefix=*/"",
35106c3fb27SDimitry Andric                                             /*NativeObjectPrefix=*/"",
35206c3fb27SDimitry Andric                                             ThinLTOEmitImports,
35306c3fb27SDimitry Andric                                             /*LinkedObjectsFile=*/nullptr,
35406c3fb27SDimitry Andric                                             /*OnWrite=*/{});
3550b57cec5SDimitry Andric   else
3565ffd83dbSDimitry Andric     Backend = createInProcessThinBackend(
35781ad6265SDimitry Andric         llvm::heavyweight_hardware_concurrency(Threads),
35881ad6265SDimitry Andric         /* OnWrite */ {}, ThinLTOEmitIndexes, ThinLTOEmitImports);
35981ad6265SDimitry Andric 
3600eae32dcSDimitry Andric   // Track whether we hit an error; in particular, in the multi-threaded case,
3610eae32dcSDimitry Andric   // we can't exit() early because the rest of the threads wouldn't have had a
3620eae32dcSDimitry Andric   // change to be join-ed, and that would result in a "terminate called without
3630eae32dcSDimitry Andric   // an active exception". Altogether, this results in nondeterministic
3640eae32dcSDimitry Andric   // behavior. Instead, we don't exit in the multi-threaded case, but we make
3650eae32dcSDimitry Andric   // sure to report the error and then at the end (after joining cleanly)
3660eae32dcSDimitry Andric   // exit(1).
3670eae32dcSDimitry Andric   std::atomic<bool> HasErrors;
3680eae32dcSDimitry Andric   std::atomic_init(&HasErrors, false);
3690eae32dcSDimitry Andric   Conf.DiagHandler = [&](const DiagnosticInfo &DI) {
3700eae32dcSDimitry Andric     DiagnosticPrinterRawOStream DP(errs());
3710eae32dcSDimitry Andric     DI.print(DP);
3720eae32dcSDimitry Andric     errs() << '\n';
3730eae32dcSDimitry Andric     if (DI.getSeverity() == DS_Error)
3740eae32dcSDimitry Andric       HasErrors = true;
3750eae32dcSDimitry Andric   };
3760eae32dcSDimitry Andric 
37706c3fb27SDimitry Andric   LTO::LTOKind LTOMode = LTO::LTOK_Default;
37806c3fb27SDimitry Andric 
37906c3fb27SDimitry Andric   if (UnifiedLTOMode == "full") {
38006c3fb27SDimitry Andric     LTOMode = LTO::LTOK_UnifiedRegular;
38106c3fb27SDimitry Andric   } else if (UnifiedLTOMode == "thin") {
38206c3fb27SDimitry Andric     LTOMode = LTO::LTOK_UnifiedThin;
38306c3fb27SDimitry Andric   } else if (UnifiedLTOMode == "default") {
38406c3fb27SDimitry Andric     LTOMode = LTO::LTOK_Default;
38506c3fb27SDimitry Andric   } else if (!UnifiedLTOMode.empty()) {
38606c3fb27SDimitry Andric     llvm::errs() << "invalid LTO mode\n";
38706c3fb27SDimitry Andric     return 1;
38806c3fb27SDimitry Andric   }
38906c3fb27SDimitry Andric 
39006c3fb27SDimitry Andric   LTO Lto(std::move(Conf), std::move(Backend), 1, LTOMode);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   for (std::string F : InputFilenames) {
3930b57cec5SDimitry Andric     std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
3940b57cec5SDimitry Andric     std::unique_ptr<InputFile> Input =
3950b57cec5SDimitry Andric         check(InputFile::create(MB->getMemBufferRef()), F);
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric     std::vector<SymbolResolution> Res;
3980b57cec5SDimitry Andric     for (const InputFile::Symbol &Sym : Input->symbols()) {
3995ffd83dbSDimitry Andric       auto I = CommandLineResolutions.find({F, std::string(Sym.getName())});
400fe6060f1SDimitry Andric       // If it isn't found, look for ".", which would have been added
4018bcb0991SDimitry Andric       // (followed by a hash) when the symbol was promoted during module
4028bcb0991SDimitry Andric       // splitting if it was defined in one part and used in the other.
403fe6060f1SDimitry Andric       // Try looking up the symbol name before the suffix.
4048bcb0991SDimitry Andric       if (I == CommandLineResolutions.end()) {
405fe6060f1SDimitry Andric         auto SplitName = Sym.getName().rsplit(".");
4065ffd83dbSDimitry Andric         I = CommandLineResolutions.find({F, std::string(SplitName.first)});
4078bcb0991SDimitry Andric       }
4080b57cec5SDimitry Andric       if (I == CommandLineResolutions.end()) {
4090b57cec5SDimitry Andric         llvm::errs() << argv[0] << ": missing symbol resolution for " << F
4100b57cec5SDimitry Andric                      << ',' << Sym.getName() << '\n';
4110b57cec5SDimitry Andric         HasErrors = true;
4120b57cec5SDimitry Andric       } else {
4130b57cec5SDimitry Andric         Res.push_back(I->second.front());
4140b57cec5SDimitry Andric         I->second.pop_front();
4150b57cec5SDimitry Andric         if (I->second.empty())
4160b57cec5SDimitry Andric           CommandLineResolutions.erase(I);
4170b57cec5SDimitry Andric       }
4180b57cec5SDimitry Andric     }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric     if (HasErrors)
4210b57cec5SDimitry Andric       continue;
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric     MBs.push_back(std::move(MB));
4240b57cec5SDimitry Andric     check(Lto.add(std::move(Input), Res), F);
4250b57cec5SDimitry Andric   }
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   if (!CommandLineResolutions.empty()) {
4280b57cec5SDimitry Andric     HasErrors = true;
4290b57cec5SDimitry Andric     for (auto UnusedRes : CommandLineResolutions)
4300b57cec5SDimitry Andric       llvm::errs() << argv[0] << ": unused symbol resolution for "
4310b57cec5SDimitry Andric                    << UnusedRes.first.first << ',' << UnusedRes.first.second
4320b57cec5SDimitry Andric                    << '\n';
4330b57cec5SDimitry Andric   }
4340b57cec5SDimitry Andric   if (HasErrors)
4350b57cec5SDimitry Andric     return 1;
4360b57cec5SDimitry Andric 
437bdd1243dSDimitry Andric   auto AddStream =
438bdd1243dSDimitry Andric       [&](size_t Task,
439bdd1243dSDimitry Andric           const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
4400b57cec5SDimitry Andric     std::string Path = OutputFilename + "." + utostr(Task);
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric     std::error_code EC;
4438bcb0991SDimitry Andric     auto S = std::make_unique<raw_fd_ostream>(Path, EC, sys::fs::OF_None);
4440b57cec5SDimitry Andric     check(EC, Path);
4450eae32dcSDimitry Andric     return std::make_unique<CachedFileStream>(std::move(S), Path);
4460b57cec5SDimitry Andric   };
4470b57cec5SDimitry Andric 
448bdd1243dSDimitry Andric   auto AddBuffer = [&](size_t Task, const Twine &ModuleName,
449bdd1243dSDimitry Andric                        std::unique_ptr<MemoryBuffer> MB) {
450bdd1243dSDimitry Andric     *AddStream(Task, ModuleName)->OS << MB->getBuffer();
4510b57cec5SDimitry Andric   };
4520b57cec5SDimitry Andric 
453349cc55cSDimitry Andric   FileCache Cache;
4540b57cec5SDimitry Andric   if (!CacheDir.empty())
455349cc55cSDimitry Andric     Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),
456349cc55cSDimitry Andric                   "failed to create cache");
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   check(Lto.run(AddStream, Cache), "LTO::run failed");
4590eae32dcSDimitry Andric   return static_cast<int>(HasErrors);
4600b57cec5SDimitry Andric }
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric static int dumpSymtab(int argc, char **argv) {
4630b57cec5SDimitry Andric   for (StringRef F : make_range(argv + 1, argv + argc)) {
4645ffd83dbSDimitry Andric     std::unique_ptr<MemoryBuffer> MB =
4655ffd83dbSDimitry Andric         check(MemoryBuffer::getFile(F), std::string(F));
4665ffd83dbSDimitry Andric     BitcodeFileContents BFC =
4675ffd83dbSDimitry Andric         check(getBitcodeFileContents(*MB), std::string(F));
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric     if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) {
4700b57cec5SDimitry Andric       auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>(
4710b57cec5SDimitry Andric           BFC.Symtab.data());
4720b57cec5SDimitry Andric       outs() << "version: " << Hdr->Version << '\n';
4730b57cec5SDimitry Andric       if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion)
4740b57cec5SDimitry Andric         outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab)
4750b57cec5SDimitry Andric                << '\n';
4760b57cec5SDimitry Andric     }
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric     std::unique_ptr<InputFile> Input =
4795ffd83dbSDimitry Andric         check(InputFile::create(MB->getMemBufferRef()), std::string(F));
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric     outs() << "target triple: " << Input->getTargetTriple() << '\n';
4820b57cec5SDimitry Andric     Triple TT(Input->getTargetTriple());
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric     outs() << "source filename: " << Input->getSourceFileName() << '\n';
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric     if (TT.isOSBinFormatCOFF())
4870b57cec5SDimitry Andric       outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric     if (TT.isOSBinFormatELF()) {
4900b57cec5SDimitry Andric       outs() << "dependent libraries:";
4910b57cec5SDimitry Andric       for (auto L : Input->getDependentLibraries())
4920b57cec5SDimitry Andric         outs() << " \"" << L << "\"";
4930b57cec5SDimitry Andric       outs() << '\n';
4940b57cec5SDimitry Andric     }
4950b57cec5SDimitry Andric 
496fe6060f1SDimitry Andric     ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable =
497fe6060f1SDimitry Andric         Input->getComdatTable();
4980b57cec5SDimitry Andric     for (const InputFile::Symbol &Sym : Input->symbols()) {
4990b57cec5SDimitry Andric       switch (Sym.getVisibility()) {
5000b57cec5SDimitry Andric       case GlobalValue::HiddenVisibility:
5010b57cec5SDimitry Andric         outs() << 'H';
5020b57cec5SDimitry Andric         break;
5030b57cec5SDimitry Andric       case GlobalValue::ProtectedVisibility:
5040b57cec5SDimitry Andric         outs() << 'P';
5050b57cec5SDimitry Andric         break;
5060b57cec5SDimitry Andric       case GlobalValue::DefaultVisibility:
5070b57cec5SDimitry Andric         outs() << 'D';
5080b57cec5SDimitry Andric         break;
5090b57cec5SDimitry Andric       }
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric       auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };
5120b57cec5SDimitry Andric       PrintBool('U', Sym.isUndefined());
5130b57cec5SDimitry Andric       PrintBool('C', Sym.isCommon());
5140b57cec5SDimitry Andric       PrintBool('W', Sym.isWeak());
5150b57cec5SDimitry Andric       PrintBool('I', Sym.isIndirect());
5160b57cec5SDimitry Andric       PrintBool('O', Sym.canBeOmittedFromSymbolTable());
5170b57cec5SDimitry Andric       PrintBool('T', Sym.isTLS());
5180b57cec5SDimitry Andric       PrintBool('X', Sym.isExecutable());
5190b57cec5SDimitry Andric       outs() << ' ' << Sym.getName() << '\n';
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric       if (Sym.isCommon())
5220b57cec5SDimitry Andric         outs() << "         size " << Sym.getCommonSize() << " align "
5230b57cec5SDimitry Andric                << Sym.getCommonAlignment() << '\n';
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric       int Comdat = Sym.getComdatIndex();
526fe6060f1SDimitry Andric       if (Comdat != -1) {
527fe6060f1SDimitry Andric         outs() << "         comdat ";
528fe6060f1SDimitry Andric         switch (ComdatTable[Comdat].second) {
529fe6060f1SDimitry Andric         case Comdat::Any:
530fe6060f1SDimitry Andric           outs() << "any";
531fe6060f1SDimitry Andric           break;
532fe6060f1SDimitry Andric         case Comdat::ExactMatch:
533fe6060f1SDimitry Andric           outs() << "exactmatch";
534fe6060f1SDimitry Andric           break;
535fe6060f1SDimitry Andric         case Comdat::Largest:
536fe6060f1SDimitry Andric           outs() << "largest";
537fe6060f1SDimitry Andric           break;
538fe6060f1SDimitry Andric         case Comdat::NoDeduplicate:
539fe6060f1SDimitry Andric           outs() << "nodeduplicate";
540fe6060f1SDimitry Andric           break;
541fe6060f1SDimitry Andric         case Comdat::SameSize:
542fe6060f1SDimitry Andric           outs() << "samesize";
543fe6060f1SDimitry Andric           break;
544fe6060f1SDimitry Andric         }
545fe6060f1SDimitry Andric         outs() << ' ' << ComdatTable[Comdat].first << '\n';
546fe6060f1SDimitry Andric       }
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric       if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
5490b57cec5SDimitry Andric         outs() << "         fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric       if (!Sym.getSectionName().empty())
5520b57cec5SDimitry Andric         outs() << "         section " << Sym.getSectionName() << "\n";
5530b57cec5SDimitry Andric     }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric     outs() << '\n';
5560b57cec5SDimitry Andric   }
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   return 0;
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric int main(int argc, char **argv) {
5620b57cec5SDimitry Andric   InitLLVM X(argc, argv);
5630b57cec5SDimitry Andric   InitializeAllTargets();
5640b57cec5SDimitry Andric   InitializeAllTargetMCs();
5650b57cec5SDimitry Andric   InitializeAllAsmPrinters();
5660b57cec5SDimitry Andric   InitializeAllAsmParsers();
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // FIXME: This should use llvm::cl subcommands, but it isn't currently
5690b57cec5SDimitry Andric   // possible to pass an argument not associated with a subcommand to a
5700b57cec5SDimitry Andric   // subcommand (e.g. -use-new-pm).
5710b57cec5SDimitry Andric   if (argc < 2)
5720b57cec5SDimitry Andric     return usage();
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric   StringRef Subcommand = argv[1];
5750b57cec5SDimitry Andric   // Ensure that argv[0] is correct after adjusting argv/argc.
5760b57cec5SDimitry Andric   argv[1] = argv[0];
5770b57cec5SDimitry Andric   if (Subcommand == "dump-symtab")
5780b57cec5SDimitry Andric     return dumpSymtab(argc - 1, argv + 1);
5790b57cec5SDimitry Andric   if (Subcommand == "run")
5800b57cec5SDimitry Andric     return run(argc - 1, argv + 1);
5810b57cec5SDimitry Andric   return usage();
5820b57cec5SDimitry Andric }
583