xref: /aosp_15_r20/external/llvm/tools/llvm-lto/llvm-lto.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1 //===-- llvm-lto: a simple command-line program to link modules with LTO --===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This program takes in a list of bitcode files, links them, performs link-time
11 // optimization, and outputs an object file.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/ADT/StringSet.h"
16 #include "llvm/Bitcode/ReaderWriter.h"
17 #include "llvm/CodeGen/CommandFlags.h"
18 #include "llvm/IR/DiagnosticPrinter.h"
19 #include "llvm/IR/LLVMContext.h"
20 #include "llvm/IR/Verifier.h"
21 #include "llvm/IRReader/IRReader.h"
22 #include "llvm/LTO/legacy/LTOCodeGenerator.h"
23 #include "llvm/LTO/legacy/LTOModule.h"
24 #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
25 #include "llvm/Object/ModuleSummaryIndexObjectFile.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/ManagedStatic.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/PrettyStackTrace.h"
31 #include "llvm/Support/Signals.h"
32 #include "llvm/Support/SourceMgr.h"
33 #include "llvm/Support/TargetSelect.h"
34 #include "llvm/Support/ToolOutputFile.h"
35 #include "llvm/Support/raw_ostream.h"
36 #include <list>
37 
38 using namespace llvm;
39 
40 static cl::opt<char>
41     OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
42                            "(default = '-O2')"),
43              cl::Prefix, cl::ZeroOrMore, cl::init('2'));
44 
45 static cl::opt<bool> DisableVerify(
46     "disable-verify", cl::init(false),
47     cl::desc("Do not run the verifier during the optimization pipeline"));
48 
49 static cl::opt<bool> DisableInline("disable-inlining", cl::init(false),
50                                    cl::desc("Do not run the inliner pass"));
51 
52 static cl::opt<bool>
53     DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
54                       cl::desc("Do not run the GVN load PRE pass"));
55 
56 static cl::opt<bool> DisableLTOVectorization(
57     "disable-lto-vectorization", cl::init(false),
58     cl::desc("Do not run loop or slp vectorization during LTO"));
59 
60 static cl::opt<bool> UseDiagnosticHandler(
61     "use-diagnostic-handler", cl::init(false),
62     cl::desc("Use a diagnostic handler to test the handler interface"));
63 
64 static cl::opt<bool>
65     ThinLTO("thinlto", cl::init(false),
66             cl::desc("Only write combined global index for ThinLTO backends"));
67 
68 enum ThinLTOModes {
69   THINLINK,
70   THINDISTRIBUTE,
71   THINEMITIMPORTS,
72   THINPROMOTE,
73   THINIMPORT,
74   THININTERNALIZE,
75   THINOPT,
76   THINCODEGEN,
77   THINALL
78 };
79 
80 cl::opt<ThinLTOModes> ThinLTOMode(
81     "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),
82     cl::values(
83         clEnumValN(
84             THINLINK, "thinlink",
85             "ThinLink: produces the index by linking only the summaries."),
86         clEnumValN(THINDISTRIBUTE, "distributedindexes",
87                    "Produces individual indexes for distributed backends."),
88         clEnumValN(THINEMITIMPORTS, "emitimports",
89                    "Emit imports files for distributed backends."),
90         clEnumValN(THINPROMOTE, "promote",
91                    "Perform pre-import promotion (requires -thinlto-index)."),
92         clEnumValN(THINIMPORT, "import", "Perform both promotion and "
93                                          "cross-module importing (requires "
94                                          "-thinlto-index)."),
95         clEnumValN(THININTERNALIZE, "internalize",
96                    "Perform internalization driven by -exported-symbol "
97                    "(requires -thinlto-index)."),
98         clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),
99         clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),
100         clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end"),
101         clEnumValEnd));
102 
103 static cl::opt<std::string>
104     ThinLTOIndex("thinlto-index",
105                  cl::desc("Provide the index produced by a ThinLink, required "
106                           "to perform the promotion and/or importing."));
107 
108 static cl::opt<std::string> ThinLTOPrefixReplace(
109     "thinlto-prefix-replace",
110     cl::desc("Control where files for distributed backends are "
111              "created. Expects 'oldprefix;newprefix' and if path "
112              "prefix of output file is oldprefix it will be "
113              "replaced with newprefix."));
114 
115 static cl::opt<std::string> ThinLTOModuleId(
116     "thinlto-module-id",
117     cl::desc("For the module ID for the file to process, useful to "
118              "match what is in the index."));
119 
120 static cl::opt<std::string>
121     ThinLTOCacheDir("thinlto-cache-dir", cl::desc("Enable ThinLTO caching."));
122 
123 static cl::opt<bool>
124     SaveModuleFile("save-merged-module", cl::init(false),
125                    cl::desc("Write merged LTO module to file before CodeGen"));
126 
127 static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
128                                             cl::desc("<input bitcode files>"));
129 
130 static cl::opt<std::string> OutputFilename("o", cl::init(""),
131                                            cl::desc("Override output filename"),
132                                            cl::value_desc("filename"));
133 
134 static cl::list<std::string> ExportedSymbols(
135     "exported-symbol",
136     cl::desc("List of symbols to export from the resulting object file"),
137     cl::ZeroOrMore);
138 
139 static cl::list<std::string>
140     DSOSymbols("dso-symbol",
141                cl::desc("Symbol to put in the symtab in the resulting dso"),
142                cl::ZeroOrMore);
143 
144 static cl::opt<bool> ListSymbolsOnly(
145     "list-symbols-only", cl::init(false),
146     cl::desc("Instead of running LTO, list the symbols in each IR file"));
147 
148 static cl::opt<bool> SetMergedModule(
149     "set-merged-module", cl::init(false),
150     cl::desc("Use the first input module as the merged module"));
151 
152 static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
153                                      cl::desc("Number of backend threads"));
154 
155 static cl::opt<bool> RestoreGlobalsLinkage(
156     "restore-linkage", cl::init(false),
157     cl::desc("Restore original linkage of globals prior to CodeGen"));
158 
159 static cl::opt<bool> CheckHasObjC(
160     "check-for-objc", cl::init(false),
161     cl::desc("Only check if the module has objective-C defined in it"));
162 
163 namespace {
164 struct ModuleInfo {
165   std::vector<bool> CanBeHidden;
166 };
167 }
168 
handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,const char * Msg,void *)169 static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
170                               const char *Msg, void *) {
171   errs() << "llvm-lto: ";
172   switch (Severity) {
173   case LTO_DS_NOTE:
174     errs() << "note: ";
175     break;
176   case LTO_DS_REMARK:
177     errs() << "remark: ";
178     break;
179   case LTO_DS_ERROR:
180     errs() << "error: ";
181     break;
182   case LTO_DS_WARNING:
183     errs() << "warning: ";
184     break;
185   }
186   errs() << Msg << "\n";
187 }
188 
189 static std::string CurrentActivity;
diagnosticHandler(const DiagnosticInfo & DI)190 static void diagnosticHandler(const DiagnosticInfo &DI) {
191   raw_ostream &OS = errs();
192   OS << "llvm-lto: ";
193   switch (DI.getSeverity()) {
194   case DS_Error:
195     OS << "error";
196     break;
197   case DS_Warning:
198     OS << "warning";
199     break;
200   case DS_Remark:
201     OS << "remark";
202     break;
203   case DS_Note:
204     OS << "note";
205     break;
206   }
207   if (!CurrentActivity.empty())
208     OS << ' ' << CurrentActivity;
209   OS << ": ";
210 
211   DiagnosticPrinterRawOStream DP(OS);
212   DI.print(DP);
213   OS << '\n';
214 
215   if (DI.getSeverity() == DS_Error)
216     exit(1);
217 }
218 
diagnosticHandlerWithContext(const DiagnosticInfo & DI,void * Context)219 static void diagnosticHandlerWithContext(const DiagnosticInfo &DI,
220                                          void *Context) {
221   diagnosticHandler(DI);
222 }
223 
error(const Twine & Msg)224 static void error(const Twine &Msg) {
225   errs() << "llvm-lto: " << Msg << '\n';
226   exit(1);
227 }
228 
error(std::error_code EC,const Twine & Prefix)229 static void error(std::error_code EC, const Twine &Prefix) {
230   if (EC)
231     error(Prefix + ": " + EC.message());
232 }
233 
234 template <typename T>
error(const ErrorOr<T> & V,const Twine & Prefix)235 static void error(const ErrorOr<T> &V, const Twine &Prefix) {
236   error(V.getError(), Prefix);
237 }
238 
maybeVerifyModule(const Module & Mod)239 static void maybeVerifyModule(const Module &Mod) {
240   if (!DisableVerify && verifyModule(Mod))
241     error("Broken Module");
242 }
243 
244 static std::unique_ptr<LTOModule>
getLocalLTOModule(StringRef Path,std::unique_ptr<MemoryBuffer> & Buffer,const TargetOptions & Options)245 getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
246                   const TargetOptions &Options) {
247   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
248       MemoryBuffer::getFile(Path);
249   error(BufferOrErr, "error loading file '" + Path + "'");
250   Buffer = std::move(BufferOrErr.get());
251   CurrentActivity = ("loading file '" + Path + "'").str();
252   std::unique_ptr<LLVMContext> Context = llvm::make_unique<LLVMContext>();
253   Context->setDiagnosticHandler(diagnosticHandlerWithContext, nullptr, true);
254   ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
255       std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),
256       Options, Path);
257   CurrentActivity = "";
258   maybeVerifyModule((*Ret)->getModule());
259   return std::move(*Ret);
260 }
261 
262 /// \brief List symbols in each IR file.
263 ///
264 /// The main point here is to provide lit-testable coverage for the LTOModule
265 /// functionality that's exposed by the C API to list symbols.  Moreover, this
266 /// provides testing coverage for modules that have been created in their own
267 /// contexts.
listSymbols(const TargetOptions & Options)268 static void listSymbols(const TargetOptions &Options) {
269   for (auto &Filename : InputFilenames) {
270     std::unique_ptr<MemoryBuffer> Buffer;
271     std::unique_ptr<LTOModule> Module =
272         getLocalLTOModule(Filename, Buffer, Options);
273 
274     // List the symbols.
275     outs() << Filename << ":\n";
276     for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
277       outs() << Module->getSymbolName(I) << "\n";
278   }
279 }
280 
281 /// Create a combined index file from the input IR files and write it.
282 ///
283 /// This is meant to enable testing of ThinLTO combined index generation,
284 /// currently available via the gold plugin via -thinlto.
createCombinedModuleSummaryIndex()285 static void createCombinedModuleSummaryIndex() {
286   ModuleSummaryIndex CombinedIndex;
287   uint64_t NextModuleId = 0;
288   for (auto &Filename : InputFilenames) {
289     CurrentActivity = "loading file '" + Filename + "'";
290     ErrorOr<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
291         llvm::getModuleSummaryIndexForFile(Filename, diagnosticHandler);
292     error(IndexOrErr, "error " + CurrentActivity);
293     std::unique_ptr<ModuleSummaryIndex> Index = std::move(IndexOrErr.get());
294     CurrentActivity = "";
295     // Skip files without a module summary.
296     if (!Index)
297       continue;
298     CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
299   }
300   std::error_code EC;
301   assert(!OutputFilename.empty());
302   raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
303                     sys::fs::OpenFlags::F_None);
304   error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
305   WriteIndexToFile(CombinedIndex, OS);
306   OS.close();
307 }
308 
309 /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
310 /// \p NewPrefix strings, if it was specified.
getThinLTOOldAndNewPrefix(std::string & OldPrefix,std::string & NewPrefix)311 static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
312                                       std::string &NewPrefix) {
313   assert(ThinLTOPrefixReplace.empty() ||
314          ThinLTOPrefixReplace.find(";") != StringRef::npos);
315   StringRef PrefixReplace = ThinLTOPrefixReplace;
316   std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");
317   OldPrefix = Split.first.str();
318   NewPrefix = Split.second.str();
319 }
320 
321 /// Given the original \p Path to an output file, replace any path
322 /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
323 /// resulting directory if it does not yet exist.
getThinLTOOutputFile(const std::string & Path,const std::string & OldPrefix,const std::string & NewPrefix)324 static std::string getThinLTOOutputFile(const std::string &Path,
325                                         const std::string &OldPrefix,
326                                         const std::string &NewPrefix) {
327   if (OldPrefix.empty() && NewPrefix.empty())
328     return Path;
329   SmallString<128> NewPath(Path);
330   llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
331   StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
332   if (!ParentPath.empty()) {
333     // Make sure the new directory exists, creating it if necessary.
334     if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
335       error(EC, "error creating the directory '" + ParentPath + "'");
336   }
337   return NewPath.str();
338 }
339 
340 namespace thinlto {
341 
342 std::vector<std::unique_ptr<MemoryBuffer>>
loadAllFilesForIndex(const ModuleSummaryIndex & Index)343 loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
344   std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
345 
346   for (auto &ModPath : Index.modulePaths()) {
347     const auto &Filename = ModPath.first();
348     auto CurrentActivity = "loading file '" + Filename + "'";
349     auto InputOrErr = MemoryBuffer::getFile(Filename);
350     error(InputOrErr, "error " + CurrentActivity);
351     InputBuffers.push_back(std::move(*InputOrErr));
352   }
353   return InputBuffers;
354 }
355 
loadCombinedIndex()356 std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
357   if (ThinLTOIndex.empty())
358     report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");
359   auto CurrentActivity = "loading file '" + ThinLTOIndex + "'";
360   ErrorOr<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
361       llvm::getModuleSummaryIndexForFile(ThinLTOIndex, diagnosticHandler);
362   error(IndexOrErr, "error " + CurrentActivity);
363   return std::move(IndexOrErr.get());
364 }
365 
loadModule(StringRef Filename,LLVMContext & Ctx)366 static std::unique_ptr<Module> loadModule(StringRef Filename,
367                                           LLVMContext &Ctx) {
368   SMDiagnostic Err;
369   std::unique_ptr<Module> M(parseIRFile(Filename, Err, Ctx));
370   if (!M) {
371     Err.print("llvm-lto", errs());
372     report_fatal_error("Can't load module for file " + Filename);
373   }
374   maybeVerifyModule(*M);
375 
376   if (ThinLTOModuleId.getNumOccurrences()) {
377     if (InputFilenames.size() != 1)
378       report_fatal_error("Can't override the module id for multiple files");
379     M->setModuleIdentifier(ThinLTOModuleId);
380   }
381   return M;
382 }
383 
writeModuleToFile(Module & TheModule,StringRef Filename)384 static void writeModuleToFile(Module &TheModule, StringRef Filename) {
385   std::error_code EC;
386   raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::F_None);
387   error(EC, "error opening the file '" + Filename + "'");
388   maybeVerifyModule(TheModule);
389   WriteBitcodeToFile(&TheModule, OS, /* ShouldPreserveUseListOrder */ true);
390 }
391 
392 class ThinLTOProcessing {
393 public:
394   ThinLTOCodeGenerator ThinGenerator;
395 
ThinLTOProcessing(const TargetOptions & Options)396   ThinLTOProcessing(const TargetOptions &Options) {
397     ThinGenerator.setCodePICModel(getRelocModel());
398     ThinGenerator.setTargetOptions(Options);
399     ThinGenerator.setCacheDir(ThinLTOCacheDir);
400 
401     // Add all the exported symbols to the table of symbols to preserve.
402     for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
403       ThinGenerator.preserveSymbol(ExportedSymbols[i]);
404   }
405 
run()406   void run() {
407     switch (ThinLTOMode) {
408     case THINLINK:
409       return thinLink();
410     case THINDISTRIBUTE:
411       return distributedIndexes();
412     case THINEMITIMPORTS:
413       return emitImports();
414     case THINPROMOTE:
415       return promote();
416     case THINIMPORT:
417       return import();
418     case THININTERNALIZE:
419       return internalize();
420     case THINOPT:
421       return optimize();
422     case THINCODEGEN:
423       return codegen();
424     case THINALL:
425       return runAll();
426     }
427   }
428 
429 private:
430   /// Load the input files, create the combined index, and write it out.
thinLink()431   void thinLink() {
432     // Perform "ThinLink": just produce the index
433     if (OutputFilename.empty())
434       report_fatal_error(
435           "OutputFilename is necessary to store the combined index.\n");
436 
437     LLVMContext Ctx;
438     std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
439     for (unsigned i = 0; i < InputFilenames.size(); ++i) {
440       auto &Filename = InputFilenames[i];
441       StringRef CurrentActivity = "loading file '" + Filename + "'";
442       auto InputOrErr = MemoryBuffer::getFile(Filename);
443       error(InputOrErr, "error " + CurrentActivity);
444       InputBuffers.push_back(std::move(*InputOrErr));
445       ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
446     }
447 
448     auto CombinedIndex = ThinGenerator.linkCombinedIndex();
449     std::error_code EC;
450     raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::F_None);
451     error(EC, "error opening the file '" + OutputFilename + "'");
452     WriteIndexToFile(*CombinedIndex, OS);
453     return;
454   }
455 
456   /// Load the combined index from disk, then compute and generate
457   /// individual index files suitable for ThinLTO distributed backend builds
458   /// on the files mentioned on the command line (these must match the index
459   /// content).
distributedIndexes()460   void distributedIndexes() {
461     if (InputFilenames.size() != 1 && !OutputFilename.empty())
462       report_fatal_error("Can't handle a single output filename and multiple "
463                          "input files, do not provide an output filename and "
464                          "the output files will be suffixed from the input "
465                          "ones.");
466 
467     std::string OldPrefix, NewPrefix;
468     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
469 
470     auto Index = loadCombinedIndex();
471     for (auto &Filename : InputFilenames) {
472       // Build a map of module to the GUIDs and summary objects that should
473       // be written to its index.
474       std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
475       ThinLTOCodeGenerator::gatherImportedSummariesForModule(
476           Filename, *Index, ModuleToSummariesForIndex);
477 
478       std::string OutputName = OutputFilename;
479       if (OutputName.empty()) {
480         OutputName = Filename + ".thinlto.bc";
481       }
482       OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
483       std::error_code EC;
484       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None);
485       error(EC, "error opening the file '" + OutputName + "'");
486       WriteIndexToFile(*Index, OS, &ModuleToSummariesForIndex);
487     }
488   }
489 
490   /// Load the combined index from disk, compute the imports, and emit
491   /// the import file lists for each module to disk.
emitImports()492   void emitImports() {
493     if (InputFilenames.size() != 1 && !OutputFilename.empty())
494       report_fatal_error("Can't handle a single output filename and multiple "
495                          "input files, do not provide an output filename and "
496                          "the output files will be suffixed from the input "
497                          "ones.");
498 
499     std::string OldPrefix, NewPrefix;
500     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
501 
502     auto Index = loadCombinedIndex();
503     for (auto &Filename : InputFilenames) {
504       std::string OutputName = OutputFilename;
505       if (OutputName.empty()) {
506         OutputName = Filename + ".imports";
507       }
508       OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
509       ThinLTOCodeGenerator::emitImports(Filename, OutputName, *Index);
510     }
511   }
512 
513   /// Load the combined index from disk, then load every file referenced by
514   /// the index and add them to the generator, finally perform the promotion
515   /// on the files mentioned on the command line (these must match the index
516   /// content).
promote()517   void promote() {
518     if (InputFilenames.size() != 1 && !OutputFilename.empty())
519       report_fatal_error("Can't handle a single output filename and multiple "
520                          "input files, do not provide an output filename and "
521                          "the output files will be suffixed from the input "
522                          "ones.");
523 
524     auto Index = loadCombinedIndex();
525     for (auto &Filename : InputFilenames) {
526       LLVMContext Ctx;
527       auto TheModule = loadModule(Filename, Ctx);
528 
529       ThinGenerator.promote(*TheModule, *Index);
530 
531       std::string OutputName = OutputFilename;
532       if (OutputName.empty()) {
533         OutputName = Filename + ".thinlto.promoted.bc";
534       }
535       writeModuleToFile(*TheModule, OutputName);
536     }
537   }
538 
539   /// Load the combined index from disk, then load every file referenced by
540   /// the index and add them to the generator, then performs the promotion and
541   /// cross module importing on the files mentioned on the command line
542   /// (these must match the index content).
import()543   void import() {
544     if (InputFilenames.size() != 1 && !OutputFilename.empty())
545       report_fatal_error("Can't handle a single output filename and multiple "
546                          "input files, do not provide an output filename and "
547                          "the output files will be suffixed from the input "
548                          "ones.");
549 
550     auto Index = loadCombinedIndex();
551     auto InputBuffers = loadAllFilesForIndex(*Index);
552     for (auto &MemBuffer : InputBuffers)
553       ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
554                               MemBuffer->getBuffer());
555 
556     for (auto &Filename : InputFilenames) {
557       LLVMContext Ctx;
558       auto TheModule = loadModule(Filename, Ctx);
559 
560       ThinGenerator.crossModuleImport(*TheModule, *Index);
561 
562       std::string OutputName = OutputFilename;
563       if (OutputName.empty()) {
564         OutputName = Filename + ".thinlto.imported.bc";
565       }
566       writeModuleToFile(*TheModule, OutputName);
567     }
568   }
569 
internalize()570   void internalize() {
571     if (InputFilenames.size() != 1 && !OutputFilename.empty())
572       report_fatal_error("Can't handle a single output filename and multiple "
573                          "input files, do not provide an output filename and "
574                          "the output files will be suffixed from the input "
575                          "ones.");
576 
577     if (ExportedSymbols.empty())
578       errs() << "Warning: -internalize will not perform without "
579                 "-exported-symbol\n";
580 
581     auto Index = loadCombinedIndex();
582     auto InputBuffers = loadAllFilesForIndex(*Index);
583     for (auto &MemBuffer : InputBuffers)
584       ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
585                               MemBuffer->getBuffer());
586 
587     for (auto &Filename : InputFilenames) {
588       LLVMContext Ctx;
589       auto TheModule = loadModule(Filename, Ctx);
590 
591       ThinGenerator.internalize(*TheModule, *Index);
592 
593       std::string OutputName = OutputFilename;
594       if (OutputName.empty()) {
595         OutputName = Filename + ".thinlto.internalized.bc";
596       }
597       writeModuleToFile(*TheModule, OutputName);
598     }
599   }
600 
optimize()601   void optimize() {
602     if (InputFilenames.size() != 1 && !OutputFilename.empty())
603       report_fatal_error("Can't handle a single output filename and multiple "
604                          "input files, do not provide an output filename and "
605                          "the output files will be suffixed from the input "
606                          "ones.");
607     if (!ThinLTOIndex.empty())
608       errs() << "Warning: -thinlto-index ignored for optimize stage";
609 
610     for (auto &Filename : InputFilenames) {
611       LLVMContext Ctx;
612       auto TheModule = loadModule(Filename, Ctx);
613 
614       ThinGenerator.optimize(*TheModule);
615 
616       std::string OutputName = OutputFilename;
617       if (OutputName.empty()) {
618         OutputName = Filename + ".thinlto.imported.bc";
619       }
620       writeModuleToFile(*TheModule, OutputName);
621     }
622   }
623 
codegen()624   void codegen() {
625     if (InputFilenames.size() != 1 && !OutputFilename.empty())
626       report_fatal_error("Can't handle a single output filename and multiple "
627                          "input files, do not provide an output filename and "
628                          "the output files will be suffixed from the input "
629                          "ones.");
630     if (!ThinLTOIndex.empty())
631       errs() << "Warning: -thinlto-index ignored for codegen stage";
632 
633     for (auto &Filename : InputFilenames) {
634       LLVMContext Ctx;
635       auto TheModule = loadModule(Filename, Ctx);
636 
637       auto Buffer = ThinGenerator.codegen(*TheModule);
638       std::string OutputName = OutputFilename;
639       if (OutputName.empty()) {
640         OutputName = Filename + ".thinlto.o";
641       }
642       if (OutputName == "-") {
643         outs() << Buffer->getBuffer();
644         return;
645       }
646 
647       std::error_code EC;
648       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None);
649       error(EC, "error opening the file '" + OutputName + "'");
650       OS << Buffer->getBuffer();
651     }
652   }
653 
654   /// Full ThinLTO process
runAll()655   void runAll() {
656     if (!OutputFilename.empty())
657       report_fatal_error("Do not provide an output filename for ThinLTO "
658                          " processing, the output files will be suffixed from "
659                          "the input ones.");
660 
661     if (!ThinLTOIndex.empty())
662       errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
663 
664     LLVMContext Ctx;
665     std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
666     for (unsigned i = 0; i < InputFilenames.size(); ++i) {
667       auto &Filename = InputFilenames[i];
668       StringRef CurrentActivity = "loading file '" + Filename + "'";
669       auto InputOrErr = MemoryBuffer::getFile(Filename);
670       error(InputOrErr, "error " + CurrentActivity);
671       InputBuffers.push_back(std::move(*InputOrErr));
672       ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
673     }
674 
675     ThinGenerator.run();
676 
677     auto &Binaries = ThinGenerator.getProducedBinaries();
678     if (Binaries.size() != InputFilenames.size())
679       report_fatal_error("Number of output objects does not match the number "
680                          "of inputs");
681 
682     for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
683       auto OutputName = InputFilenames[BufID] + ".thinlto.o";
684       std::error_code EC;
685       raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None);
686       error(EC, "error opening the file '" + OutputName + "'");
687       OS << Binaries[BufID]->getBuffer();
688     }
689   }
690 
691   /// Load the combined index from disk, then load every file referenced by
692 };
693 
694 } // namespace thinlto
695 
main(int argc,char ** argv)696 int main(int argc, char **argv) {
697   // Print a stack trace if we signal out.
698   sys::PrintStackTraceOnErrorSignal(argv[0]);
699   PrettyStackTraceProgram X(argc, argv);
700 
701   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
702   cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
703 
704   if (OptLevel < '0' || OptLevel > '3')
705     error("optimization level must be between 0 and 3");
706 
707   // Initialize the configured targets.
708   InitializeAllTargets();
709   InitializeAllTargetMCs();
710   InitializeAllAsmPrinters();
711   InitializeAllAsmParsers();
712 
713   // set up the TargetOptions for the machine
714   TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
715 
716   if (ListSymbolsOnly) {
717     listSymbols(Options);
718     return 0;
719   }
720 
721   if (CheckHasObjC) {
722     for (auto &Filename : InputFilenames) {
723       ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
724           MemoryBuffer::getFile(Filename);
725       error(BufferOrErr, "error loading file '" + Filename + "'");
726       auto Buffer = std::move(BufferOrErr.get());
727       LLVMContext Ctx;
728       if (llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx))
729         outs() << "Bitcode " << Filename << " contains ObjC\n";
730       else
731         outs() << "Bitcode " << Filename << " does not contain ObjC\n";
732     }
733     return 0;
734   }
735 
736   if (ThinLTOMode.getNumOccurrences()) {
737     if (ThinLTOMode.getNumOccurrences() > 1)
738       report_fatal_error("You can't specify more than one -thinlto-action");
739     thinlto::ThinLTOProcessing ThinLTOProcessor(Options);
740     ThinLTOProcessor.run();
741     return 0;
742   }
743 
744   if (ThinLTO) {
745     createCombinedModuleSummaryIndex();
746     return 0;
747   }
748 
749   unsigned BaseArg = 0;
750 
751   LLVMContext Context;
752   Context.setDiagnosticHandler(diagnosticHandlerWithContext, nullptr, true);
753 
754   LTOCodeGenerator CodeGen(Context);
755 
756   if (UseDiagnosticHandler)
757     CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
758 
759   CodeGen.setCodePICModel(getRelocModel());
760 
761   CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
762   CodeGen.setTargetOptions(Options);
763   CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
764 
765   llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet;
766   for (unsigned i = 0; i < DSOSymbols.size(); ++i)
767     DSOSymbolsSet.insert(DSOSymbols[i]);
768 
769   std::vector<std::string> KeptDSOSyms;
770 
771   for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
772     CurrentActivity = "loading file '" + InputFilenames[i] + "'";
773     ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
774         LTOModule::createFromFile(Context, InputFilenames[i].c_str(), Options);
775     std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
776     CurrentActivity = "";
777 
778     unsigned NumSyms = Module->getSymbolCount();
779     for (unsigned I = 0; I < NumSyms; ++I) {
780       StringRef Name = Module->getSymbolName(I);
781       if (!DSOSymbolsSet.count(Name))
782         continue;
783       lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
784       unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
785       if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
786         KeptDSOSyms.push_back(Name);
787     }
788 
789     // We use the first input module as the destination module when
790     // SetMergedModule is true.
791     if (SetMergedModule && i == BaseArg) {
792       // Transfer ownership to the code generator.
793       CodeGen.setModule(std::move(Module));
794     } else if (!CodeGen.addModule(Module.get())) {
795       // Print a message here so that we know addModule() did not abort.
796       error("error adding file '" + InputFilenames[i] + "'");
797     }
798   }
799 
800   // Add all the exported symbols to the table of symbols to preserve.
801   for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
802     CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());
803 
804   // Add all the dso symbols to the table of symbols to expose.
805   for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
806     CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());
807 
808   // Set cpu and attrs strings for the default target/subtarget.
809   CodeGen.setCpu(MCPU.c_str());
810 
811   CodeGen.setOptLevel(OptLevel - '0');
812 
813   std::string attrs;
814   for (unsigned i = 0; i < MAttrs.size(); ++i) {
815     if (i > 0)
816       attrs.append(",");
817     attrs.append(MAttrs[i]);
818   }
819 
820   if (!attrs.empty())
821     CodeGen.setAttr(attrs.c_str());
822 
823   if (FileType.getNumOccurrences())
824     CodeGen.setFileType(FileType);
825 
826   if (!OutputFilename.empty()) {
827     if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE,
828                           DisableLTOVectorization)) {
829       // Diagnostic messages should have been printed by the handler.
830       error("error optimizing the code");
831     }
832 
833     if (SaveModuleFile) {
834       std::string ModuleFilename = OutputFilename;
835       ModuleFilename += ".merged.bc";
836       std::string ErrMsg;
837 
838       if (!CodeGen.writeMergedModules(ModuleFilename.c_str()))
839         error("writing merged module failed.");
840     }
841 
842     std::list<tool_output_file> OSs;
843     std::vector<raw_pwrite_stream *> OSPtrs;
844     for (unsigned I = 0; I != Parallelism; ++I) {
845       std::string PartFilename = OutputFilename;
846       if (Parallelism != 1)
847         PartFilename += "." + utostr(I);
848       std::error_code EC;
849       OSs.emplace_back(PartFilename, EC, sys::fs::F_None);
850       if (EC)
851         error("error opening the file '" + PartFilename + "': " + EC.message());
852       OSPtrs.push_back(&OSs.back().os());
853     }
854 
855     if (!CodeGen.compileOptimized(OSPtrs))
856       // Diagnostic messages should have been printed by the handler.
857       error("error compiling the code");
858 
859     for (tool_output_file &OS : OSs)
860       OS.keep();
861   } else {
862     if (Parallelism != 1)
863       error("-j must be specified together with -o");
864 
865     if (SaveModuleFile)
866       error(": -save-merged-module must be specified with -o");
867 
868     const char *OutputName = nullptr;
869     if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline,
870                                  DisableGVNLoadPRE, DisableLTOVectorization))
871       error("error compiling the code");
872       // Diagnostic messages should have been printed by the handler.
873 
874     outs() << "Wrote native object file '" << OutputName << "'\n";
875   }
876 
877   return 0;
878 }
879