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