1//===- llvm-lto: a simple command-line program to link modules with LTO ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This program takes in a list of bitcode files, links them, performs link-time
10// optimization, and outputs an object file.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm-c/lto.h"
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/SmallString.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/StringSet.h"
21#include "llvm/ADT/Twine.h"
22#include "llvm/Bitcode/BitcodeReader.h"
23#include "llvm/Bitcode/BitcodeWriter.h"
24#include "llvm/CodeGen/CommandFlags.h"
25#include "llvm/IR/DiagnosticInfo.h"
26#include "llvm/IR/DiagnosticPrinter.h"
27#include "llvm/IR/LLVMContext.h"
28#include "llvm/IR/Module.h"
29#include "llvm/IR/ModuleSummaryIndex.h"
30#include "llvm/IR/Verifier.h"
31#include "llvm/IRReader/IRReader.h"
32#include "llvm/LTO/legacy/LTOCodeGenerator.h"
33#include "llvm/LTO/legacy/LTOModule.h"
34#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
35#include "llvm/Support/Allocator.h"
36#include "llvm/Support/Casting.h"
37#include "llvm/Support/CommandLine.h"
38#include "llvm/Support/Error.h"
39#include "llvm/Support/ErrorHandling.h"
40#include "llvm/Support/ErrorOr.h"
41#include "llvm/Support/FileSystem.h"
42#include "llvm/Support/InitLLVM.h"
43#include "llvm/Support/LibraryOptionsContext.h"
44#include "llvm/Support/MemoryBuffer.h"
45#include "llvm/Support/Path.h"
46#include "llvm/Support/SourceMgr.h"
47#include "llvm/Support/TargetSelect.h"
48#include "llvm/Support/ToolOutputFile.h"
49#include "llvm/Support/WithColor.h"
50#include "llvm/Support/raw_ostream.h"
51#include "llvm/Target/TargetOptions.h"
52#include <algorithm>
53#include <cassert>
54#include <cstdint>
55#include <cstdlib>
56#include <memory>
57#include <string>
58#include <system_error>
59#include <tuple>
60#include <utility>
61#include <vector>
62
63using namespace llvm;
64
65static codegen::RegisterCodeGenFlags CGF;
66
67static cl::OptionCategory LTOCategory("LTO Options");
68
69static cl::opt<char>
70 OptLevel("O",
71 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
72 "(default = '-O2')"),
73 cl::Prefix, cl::init(Val: '2'), cl::cat(LTOCategory));
74
75static cl::opt<bool>
76 IndexStats("thinlto-index-stats",
77 cl::desc("Print statistic for the index in every input files"),
78 cl::init(Val: false), cl::cat(LTOCategory));
79
80static cl::opt<bool> DisableVerify(
81 "disable-verify", cl::init(Val: false),
82 cl::desc("Do not run the verifier during the optimization pipeline"),
83 cl::cat(LTOCategory));
84
85static cl::opt<bool> EnableFreestanding(
86 "lto-freestanding", cl::init(Val: false),
87 cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
88 cl::cat(LTOCategory));
89
90static cl::opt<bool> UseDiagnosticHandler(
91 "use-diagnostic-handler", cl::init(Val: false),
92 cl::desc("Use a diagnostic handler to test the handler interface"),
93 cl::cat(LTOCategory));
94
95static cl::opt<bool>
96 ThinLTO("thinlto", cl::init(Val: false),
97 cl::desc("Only write combined global index for ThinLTO backends"),
98 cl::cat(LTOCategory));
99
100enum ThinLTOModes {
101 THINLINK,
102 THINDISTRIBUTE,
103 THINEMITIMPORTS,
104 THINPROMOTE,
105 THINIMPORT,
106 THININTERNALIZE,
107 THINOPT,
108 THINCODEGEN,
109 THINALL
110};
111
112static cl::opt<ThinLTOModes> ThinLTOMode(
113 "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),
114 cl::values(
115 clEnumValN(
116 THINLINK, "thinlink",
117 "ThinLink: produces the index by linking only the summaries."),
118 clEnumValN(THINDISTRIBUTE, "distributedindexes",
119 "Produces individual indexes for distributed backends."),
120 clEnumValN(THINEMITIMPORTS, "emitimports",
121 "Emit imports files for distributed backends."),
122 clEnumValN(THINPROMOTE, "promote",
123 "Perform pre-import promotion (requires -thinlto-index)."),
124 clEnumValN(THINIMPORT, "import",
125 "Perform both promotion and "
126 "cross-module importing (requires "
127 "-thinlto-index)."),
128 clEnumValN(THININTERNALIZE, "internalize",
129 "Perform internalization driven by -exported-symbol "
130 "(requires -thinlto-index)."),
131 clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),
132 clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),
133 clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),
134 cl::cat(LTOCategory));
135
136static cl::opt<std::string>
137 ThinLTOIndex("thinlto-index",
138 cl::desc("Provide the index produced by a ThinLink, required "
139 "to perform the promotion and/or importing."),
140 cl::cat(LTOCategory));
141
142static cl::opt<std::string> ThinLTOPrefixReplace(
143 "thinlto-prefix-replace",
144 cl::desc("Control where files for distributed backends are "
145 "created. Expects 'oldprefix;newprefix' and if path "
146 "prefix of output file is oldprefix it will be "
147 "replaced with newprefix."),
148 cl::cat(LTOCategory));
149
150static cl::opt<std::string> ThinLTOModuleId(
151 "thinlto-module-id",
152 cl::desc("For the module ID for the file to process, useful to "
153 "match what is in the index."),
154 cl::cat(LTOCategory));
155
156static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",
157 cl::desc("Enable ThinLTO caching."),
158 cl::cat(LTOCategory));
159
160static cl::opt<int> ThinLTOCachePruningInterval(
161 "thinlto-cache-pruning-interval", cl::init(Val: 1200),
162 cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));
163
164static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
165 "thinlto-cache-max-size-bytes",
166 cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),
167 cl::cat(LTOCategory));
168
169static cl::opt<int> ThinLTOCacheMaxSizeFiles(
170 "thinlto-cache-max-size-files", cl::init(Val: 1000000),
171 cl::desc("Set ThinLTO cache pruning directory maximum number of files."),
172 cl::cat(LTOCategory));
173
174static cl::opt<unsigned> ThinLTOCacheEntryExpiration(
175 "thinlto-cache-entry-expiration", cl::init(Val: 604800) /* 1w */,
176 cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));
177
178static cl::opt<std::string> ThinLTOSaveTempsPrefix(
179 "thinlto-save-temps",
180 cl::desc("Save ThinLTO temp files using filenames created by adding "
181 "suffixes to the given file path prefix."),
182 cl::cat(LTOCategory));
183
184static cl::opt<std::string> ThinLTOGeneratedObjectsDir(
185 "thinlto-save-objects",
186 cl::desc("Save ThinLTO generated object files using filenames created in "
187 "the given directory."),
188 cl::cat(LTOCategory));
189
190static cl::opt<bool> SaveLinkedModuleFile(
191 "save-linked-module", cl::init(Val: false),
192 cl::desc("Write linked LTO module to file before optimize"),
193 cl::cat(LTOCategory));
194
195static cl::opt<bool>
196 SaveModuleFile("save-merged-module", cl::init(Val: false),
197 cl::desc("Write merged LTO module to file before CodeGen"),
198 cl::cat(LTOCategory));
199
200static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
201 cl::desc("<input bitcode files>"),
202 cl::cat(LTOCategory));
203
204static cl::opt<std::string> OutputFilename("o", cl::init(Val: ""),
205 cl::desc("Override output filename"),
206 cl::value_desc("filename"),
207 cl::cat(LTOCategory));
208
209static cl::list<std::string> ExportedSymbols(
210 "exported-symbol",
211 cl::desc("List of symbols to export from the resulting object file"),
212 cl::cat(LTOCategory));
213
214static cl::list<std::string>
215 DSOSymbols("dso-symbol",
216 cl::desc("Symbol to put in the symtab in the resulting dso"),
217 cl::cat(LTOCategory));
218
219static cl::opt<bool> ListSymbolsOnly(
220 "list-symbols-only", cl::init(Val: false),
221 cl::desc("Instead of running LTO, list the symbols in each IR file"),
222 cl::cat(LTOCategory));
223
224static cl::opt<bool> ListDependentLibrariesOnly(
225 "list-dependent-libraries-only", cl::init(Val: false),
226 cl::desc(
227 "Instead of running LTO, list the dependent libraries in each IR file"),
228 cl::cat(LTOCategory));
229
230static cl::opt<bool> QueryHasCtorDtor(
231 "query-hasCtorDtor", cl::init(Val: false),
232 cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));
233
234static cl::opt<bool>
235 SetMergedModule("set-merged-module", cl::init(Val: false),
236 cl::desc("Use the first input module as the merged module"),
237 cl::cat(LTOCategory));
238
239static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(Val: 1),
240 cl::desc("Number of backend threads"),
241 cl::cat(LTOCategory));
242
243static cl::opt<bool> RestoreGlobalsLinkage(
244 "restore-linkage", cl::init(Val: false),
245 cl::desc("Restore original linkage of globals prior to CodeGen"),
246 cl::cat(LTOCategory));
247
248static cl::opt<bool> CheckHasObjC(
249 "check-for-objc", cl::init(Val: false),
250 cl::desc("Only check if the module has objective-C defined in it"),
251 cl::cat(LTOCategory));
252
253static cl::opt<bool> PrintMachOCPUOnly(
254 "print-macho-cpu-only", cl::init(Val: false),
255 cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),
256 cl::cat(LTOCategory));
257
258static cl::opt<bool>
259 DebugPassManager("debug-pass-manager", cl::init(Val: false), cl::Hidden,
260 cl::desc("Print pass management debugging information"),
261 cl::cat(LTOCategory));
262
263static cl::opt<bool>
264 LTOSaveBeforeOpt("lto-save-before-opt", cl::init(Val: false),
265 cl::desc("Save the IR before running optimizations"));
266
267namespace {
268
269struct ModuleInfo {
270 BitVector CanBeHidden;
271};
272
273// An LLVMContext with the library options of the command line.
274struct ToolContext : LLVMContext {
275 explicit ToolContext(const cl::LibraryOptionsContext &LibraryOptions) {
276 getLibraryOptions().assign(Other: LibraryOptions);
277 }
278};
279
280} // end anonymous namespace
281
282static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
283 const char *Msg, void *) {
284 errs() << "llvm-lto: ";
285 switch (Severity) {
286 case LTO_DS_NOTE:
287 errs() << "note: ";
288 break;
289 case LTO_DS_REMARK:
290 errs() << "remark: ";
291 break;
292 case LTO_DS_ERROR:
293 errs() << "error: ";
294 break;
295 case LTO_DS_WARNING:
296 errs() << "warning: ";
297 break;
298 }
299 errs() << Msg << "\n";
300}
301
302static std::string CurrentActivity;
303
304namespace {
305 struct LLVMLTODiagnosticHandler : public DiagnosticHandler {
306 bool handleDiagnostics(const DiagnosticInfo &DI) override {
307 raw_ostream &OS = errs();
308 OS << "llvm-lto: ";
309 switch (DI.getSeverity()) {
310 case DS_Error:
311 OS << "error";
312 break;
313 case DS_Warning:
314 OS << "warning";
315 break;
316 case DS_Remark:
317 OS << "remark";
318 break;
319 case DS_Note:
320 OS << "note";
321 break;
322 }
323 if (!CurrentActivity.empty())
324 OS << ' ' << CurrentActivity;
325 OS << ": ";
326
327 DiagnosticPrinterRawOStream DP(OS);
328 DI.print(DP);
329 OS << '\n';
330
331 if (DI.getSeverity() == DS_Error)
332 exit(status: 1);
333 return true;
334 }
335 };
336 }
337
338static void error(const Twine &Msg) {
339 errs() << "llvm-lto: " << Msg << '\n';
340 exit(status: 1);
341}
342
343static void error(std::error_code EC, const Twine &Prefix) {
344 if (EC)
345 error(Msg: Prefix + ": " + EC.message());
346}
347
348template <typename T>
349static void error(const ErrorOr<T> &V, const Twine &Prefix) {
350 error(V.getError(), Prefix);
351}
352
353static void maybeVerifyModule(const Module &Mod) {
354 if (!DisableVerify && verifyModule(M: Mod, OS: &errs()))
355 error(Msg: "Broken Module");
356}
357
358static std::unique_ptr<LTOModule>
359getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
360 const TargetOptions &Options) {
361 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
362 MemoryBuffer::getFile(Filename: Path);
363 error(V: BufferOrErr, Prefix: "error loading file '" + Path + "'");
364 Buffer = std::move(BufferOrErr.get());
365 CurrentActivity = ("loading file '" + Path + "'").str();
366 std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
367 Context->setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
368 RespectFilters: true);
369 ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
370 Context: std::move(Context), mem: Buffer->getBufferStart(), length: Buffer->getBufferSize(),
371 options: Options, path: Path);
372 CurrentActivity = "";
373 maybeVerifyModule(Mod: (*Ret)->getModule());
374 return std::move(*Ret);
375}
376
377/// Print some statistics on the index for each input files.
378static void printIndexStats() {
379 for (auto &Filename : InputFilenames) {
380 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
381 std::unique_ptr<ModuleSummaryIndex> Index =
382 ExitOnErr(getModuleSummaryIndexForFile(Path: Filename));
383 // Skip files without a module summary.
384 if (!Index)
385 report_fatal_error(reason: Twine(Filename) + " does not contain an index");
386
387 unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
388 for (auto &Summaries : *Index) {
389 for (auto &Summary : Summaries.second.getSummaryList()) {
390 Refs += Summary->refs().size();
391 if (auto *FuncSummary = dyn_cast<FunctionSummary>(Val: Summary.get())) {
392 Functions++;
393 Calls += FuncSummary->calls().size();
394 } else if (isa<AliasSummary>(Val: Summary.get()))
395 Alias++;
396 else
397 Globals++;
398 }
399 }
400 outs() << "Index " << Filename << " contains "
401 << (Alias + Globals + Functions) << " nodes (" << Functions
402 << " functions, " << Alias << " alias, " << Globals
403 << " globals) and " << (Calls + Refs) << " edges (" << Refs
404 << " refs and " << Calls << " calls)\n";
405 }
406}
407
408/// Print the lto symbol attributes.
409static void printLTOSymbolAttributes(lto_symbol_attributes Attrs) {
410 outs() << "{ ";
411 unsigned Permission = Attrs & LTO_SYMBOL_PERMISSIONS_MASK;
412 switch (Permission) {
413 case LTO_SYMBOL_PERMISSIONS_CODE:
414 outs() << "function ";
415 break;
416 case LTO_SYMBOL_PERMISSIONS_DATA:
417 outs() << "data ";
418 break;
419 case LTO_SYMBOL_PERMISSIONS_RODATA:
420 outs() << "constant ";
421 break;
422 }
423 unsigned Definition = Attrs & LTO_SYMBOL_DEFINITION_MASK;
424 switch (Definition) {
425 case LTO_SYMBOL_DEFINITION_REGULAR:
426 outs() << "defined ";
427 break;
428 case LTO_SYMBOL_DEFINITION_TENTATIVE:
429 outs() << "common ";
430 break;
431 case LTO_SYMBOL_DEFINITION_WEAK:
432 outs() << "weak ";
433 break;
434 case LTO_SYMBOL_DEFINITION_UNDEFINED:
435 outs() << "extern ";
436 break;
437 case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
438 outs() << "extern-weak ";
439 break;
440 }
441 unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
442 switch (Scope) {
443 case LTO_SYMBOL_SCOPE_INTERNAL:
444 outs() << "internal ";
445 break;
446 case LTO_SYMBOL_SCOPE_HIDDEN:
447 outs() << "hidden ";
448 break;
449 case LTO_SYMBOL_SCOPE_PROTECTED:
450 outs() << "protected ";
451 break;
452 case LTO_SYMBOL_SCOPE_DEFAULT:
453 outs() << "default ";
454 break;
455 case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
456 outs() << "omitted ";
457 break;
458 }
459 if (Attrs & LTO_SYMBOL_COMDAT)
460 outs() << "comdat ";
461 if (Attrs & LTO_SYMBOL_ALIAS)
462 outs() << "alias ";
463 outs() << "}";
464}
465
466/// Load each IR file and dump certain information based on active flags.
467///
468/// The main point here is to provide lit-testable coverage for the LTOModule
469/// functionality that's exposed by the C API. Moreover, this provides testing
470/// coverage for modules that have been created in their own contexts.
471static void testLTOModule(const TargetOptions &Options) {
472 for (auto &Filename : InputFilenames) {
473 std::unique_ptr<MemoryBuffer> Buffer;
474 std::unique_ptr<LTOModule> Module =
475 getLocalLTOModule(Path: Filename, Buffer, Options);
476
477 if (ListSymbolsOnly) {
478 // List the symbols.
479 outs() << Filename << ":\n";
480 for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) {
481 outs() << Module->getSymbolName(index: I) << " ";
482 printLTOSymbolAttributes(Attrs: Module->getSymbolAttributes(index: I));
483 outs() << "\n";
484 }
485 for (int I = 0, E = Module->getAsmUndefSymbolCount(); I != E; ++I)
486 outs() << Module->getAsmUndefSymbolName(index: I) << " { asm extern }\n";
487 }
488 if (QueryHasCtorDtor)
489 outs() << Filename
490 << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")
491 << "\n";
492 }
493}
494
495static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
496 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
497 "': ");
498 return ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFileOrSTDIN(Filename)));
499}
500
501static void listDependentLibraries() {
502 for (auto &Filename : InputFilenames) {
503 auto Buffer = loadFile(Filename);
504 std::string E;
505 std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
506 buffer: Buffer->getBufferStart(), buffer_size: Buffer->getBufferSize(), path: Filename.c_str(),
507 out_error&: E));
508 if (!Input)
509 error(Msg: E);
510
511 // List the dependent libraries.
512 outs() << Filename << ":\n";
513 for (size_t I = 0, C = LTOModule::getDependentLibraryCount(input: Input.get());
514 I != C; ++I) {
515 size_t L = 0;
516 const char *S = LTOModule::getDependentLibrary(input: Input.get(), index: I, size: &L);
517 assert(S);
518 outs() << StringRef(S, L) << "\n";
519 }
520 }
521}
522
523static void printMachOCPUOnly() {
524 LLVMContext Context;
525 Context.setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
526 RespectFilters: true);
527 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
528 for (auto &Filename : InputFilenames) {
529 ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
530 LTOModule::createFromFile(Context, path: Filename, options: Options);
531 if (!ModuleOrErr)
532 error(V: ModuleOrErr, Prefix: "llvm-lto: ");
533
534 Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();
535 Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();
536 if (!CPUType)
537 error(Msg: "Error while printing mach-o cputype: " +
538 toString(E: CPUType.takeError()));
539 if (!CPUSubType)
540 error(Msg: "Error while printing mach-o cpusubtype: " +
541 toString(E: CPUSubType.takeError()));
542 outs() << llvm::format(Fmt: "%s:\ncputype: %u\ncpusubtype: %u\n",
543 Vals: Filename.c_str(), Vals: *CPUType, Vals: *CPUSubType);
544 }
545}
546
547/// Create a combined index file from the input IR files and write it.
548///
549/// This is meant to enable testing of ThinLTO combined index generation,
550/// currently available via the gold plugin via -thinlto.
551static void createCombinedModuleSummaryIndex() {
552 ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
553 for (auto &Filename : InputFilenames) {
554 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
555 std::unique_ptr<MemoryBuffer> MB =
556 ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFileOrSTDIN(Filename)));
557 ExitOnErr(readModuleSummaryIndex(Buffer: *MB, CombinedIndex));
558 }
559 // In order to use this index for testing, specifically import testing, we
560 // need to update any indirect call edges created from SamplePGO, so that they
561 // point to the correct GUIDs.
562 updateIndirectCalls(Index&: CombinedIndex);
563 std::error_code EC;
564 assert(!OutputFilename.empty());
565 raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
566 sys::fs::OpenFlags::OF_None);
567 error(EC, Prefix: "error opening the file '" + OutputFilename + ".thinlto.bc'");
568 writeIndexToFile(Index: CombinedIndex, Out&: OS);
569 OS.close();
570}
571
572/// Parse the thinlto_prefix_replace option into the \p OldPrefix and
573/// \p NewPrefix strings, if it was specified.
574static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
575 std::string &NewPrefix) {
576 assert(ThinLTOPrefixReplace.empty() ||
577 ThinLTOPrefixReplace.find(';') != StringRef::npos);
578 StringRef PrefixReplace = ThinLTOPrefixReplace;
579 std::pair<StringRef, StringRef> Split = PrefixReplace.split(Separator: ";");
580 OldPrefix = Split.first.str();
581 NewPrefix = Split.second.str();
582}
583
584/// Given the original \p Path to an output file, replace any path
585/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
586/// resulting directory if it does not yet exist.
587static std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix,
588 StringRef NewPrefix) {
589 if (OldPrefix.empty() && NewPrefix.empty())
590 return std::string(Path);
591 SmallString<128> NewPath(Path);
592 llvm::sys::path::replace_path_prefix(Path&: NewPath, OldPrefix, NewPrefix);
593 StringRef ParentPath = llvm::sys::path::parent_path(path: NewPath.str());
594 if (!ParentPath.empty()) {
595 // Make sure the new directory exists, creating it if necessary.
596 if (std::error_code EC = llvm::sys::fs::create_directories(path: ParentPath))
597 error(EC, Prefix: "error creating the directory '" + ParentPath + "'");
598 }
599 return std::string(NewPath);
600}
601
602namespace thinlto {
603
604std::vector<std::unique_ptr<MemoryBuffer>>
605loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
606 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
607
608 for (auto &ModPath : Index.modulePaths()) {
609 const auto &Filename = ModPath.first();
610 std::string CurrentActivity = ("loading file '" + Filename + "'").str();
611 auto InputOrErr = MemoryBuffer::getFile(Filename);
612 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
613 InputBuffers.push_back(x: std::move(*InputOrErr));
614 }
615 return InputBuffers;
616}
617
618std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
619 if (ThinLTOIndex.empty())
620 report_fatal_error(reason: "Missing -thinlto-index for ThinLTO promotion stage");
621 ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +
622 "': ");
623 return ExitOnErr(getModuleSummaryIndexForFile(Path: ThinLTOIndex));
624}
625
626static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
627 ExitOnError ExitOnErr("llvm-lto: error loading input '" +
628 Buffer.getBufferIdentifier().str() + "': ");
629 return ExitOnErr(lto::InputFile::create(Object: Buffer));
630}
631
632static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
633 LLVMContext &CTX) {
634 auto &Mod = File.getSingleBitcodeModule();
635 auto ModuleOrErr = Mod.parseModule(Context&: CTX);
636 if (!ModuleOrErr) {
637 handleAllErrors(E: ModuleOrErr.takeError(), Handlers: [&](ErrorInfoBase &EIB) {
638 SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
639 SourceMgr::DK_Error, EIB.message());
640 Err.print(ProgName: "llvm-lto", S&: errs());
641 });
642 report_fatal_error(reason: "Can't load module, abort.");
643 }
644 maybeVerifyModule(Mod: **ModuleOrErr);
645 if (ThinLTOModuleId.getNumOccurrences()) {
646 if (InputFilenames.size() != 1)
647 report_fatal_error(reason: "Can't override the module id for multiple files");
648 (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
649 }
650 return std::move(*ModuleOrErr);
651}
652
653static void writeModuleToFile(Module &TheModule, StringRef Filename) {
654 std::error_code EC;
655 raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);
656 error(EC, Prefix: "error opening the file '" + Filename + "'");
657 maybeVerifyModule(Mod: TheModule);
658 WriteBitcodeToFile(M: TheModule, Out&: OS, /* ShouldPreserveUseListOrder */ true);
659}
660
661class ThinLTOProcessing {
662public:
663 const cl::LibraryOptionsContext &LibraryOptions;
664 ThinLTOCodeGenerator ThinGenerator;
665
666 ThinLTOProcessing(const cl::LibraryOptionsContext &LibraryOptions,
667 const TargetOptions &Options)
668 : LibraryOptions(LibraryOptions), ThinGenerator(LibraryOptions) {
669 ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());
670 ThinGenerator.setTargetOptions(Options);
671 ThinGenerator.setCacheDir(ThinLTOCacheDir);
672 ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);
673 ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
674 ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
675 ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
676 ThinGenerator.setFreestanding(EnableFreestanding);
677 ThinGenerator.setDebugPassManager(DebugPassManager);
678
679 // Add all the exported symbols to the table of symbols to preserve.
680 for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
681 ThinGenerator.preserveSymbol(Name: ExportedSymbols[i]);
682 }
683
684 void run() {
685 switch (ThinLTOMode) {
686 case THINLINK:
687 return thinLink();
688 case THINDISTRIBUTE:
689 return distributedIndexes();
690 case THINEMITIMPORTS:
691 return emitImports();
692 case THINPROMOTE:
693 return promote();
694 case THINIMPORT:
695 return import();
696 case THININTERNALIZE:
697 return internalize();
698 case THINOPT:
699 return optimize();
700 case THINCODEGEN:
701 return codegen();
702 case THINALL:
703 return runAll();
704 }
705 }
706
707private:
708 /// Load the input files, create the combined index, and write it out.
709 void thinLink() {
710 // Perform "ThinLink": just produce the index
711 if (OutputFilename.empty())
712 report_fatal_error(
713 reason: "OutputFilename is necessary to store the combined index.\n");
714
715 LLVMContext Ctx;
716 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
717 for (unsigned i = 0; i < InputFilenames.size(); ++i) {
718 auto &Filename = InputFilenames[i];
719 std::string CurrentActivity = "loading file '" + Filename + "'";
720 auto InputOrErr = MemoryBuffer::getFile(Filename);
721 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
722 InputBuffers.push_back(x: std::move(*InputOrErr));
723 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
724 }
725
726 auto CombinedIndex = ThinGenerator.linkCombinedIndex();
727 if (!CombinedIndex)
728 report_fatal_error(reason: "ThinLink didn't create an index");
729 std::error_code EC;
730 raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
731 error(EC, Prefix: "error opening the file '" + OutputFilename + "'");
732 writeIndexToFile(Index: *CombinedIndex, Out&: OS);
733 }
734
735 /// Load the combined index from disk, then compute and generate
736 /// individual index files suitable for ThinLTO distributed backend builds
737 /// on the files mentioned on the command line (these must match the index
738 /// content).
739 void distributedIndexes() {
740 if (InputFilenames.size() != 1 && !OutputFilename.empty())
741 report_fatal_error(reason: "Can't handle a single output filename and multiple "
742 "input files, do not provide an output filename and "
743 "the output files will be suffixed from the input "
744 "ones.");
745
746 std::string OldPrefix, NewPrefix;
747 getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
748
749 auto Index = loadCombinedIndex();
750 for (auto &Filename : InputFilenames) {
751 ToolContext Ctx(LibraryOptions);
752 auto Buffer = loadFile(Filename);
753 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
754 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
755
756 // Build a map of module to the GUIDs and summary objects that should
757 // be written to its index.
758 ModuleToSummariesForIndexTy ModuleToSummariesForIndex;
759 GVSummaryPtrSet DecSummaries;
760 ThinGenerator.gatherImportedSummariesForModule(
761 Module&: *TheModule, Index&: *Index, ModuleToSummariesForIndex, DecSummaries, File: *Input);
762
763 std::string OutputName = OutputFilename;
764 if (OutputName.empty()) {
765 OutputName = Filename + ".thinlto.bc";
766 }
767 OutputName = getThinLTOOutputFile(Path: OutputName, OldPrefix, NewPrefix);
768 std::error_code EC;
769 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
770 error(EC, Prefix: "error opening the file '" + OutputName + "'");
771 writeIndexToFile(Index: *Index, Out&: OS, ModuleToSummariesForIndex: &ModuleToSummariesForIndex, DecSummaries: &DecSummaries);
772 }
773 }
774
775 /// Load the combined index from disk, compute the imports, and emit
776 /// the import file lists for each module to disk.
777 void emitImports() {
778 if (InputFilenames.size() != 1 && !OutputFilename.empty())
779 report_fatal_error(reason: "Can't handle a single output filename and multiple "
780 "input files, do not provide an output filename and "
781 "the output files will be suffixed from the input "
782 "ones.");
783
784 std::string OldPrefix, NewPrefix;
785 getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
786
787 auto Index = loadCombinedIndex();
788 for (auto &Filename : InputFilenames) {
789 ToolContext Ctx(LibraryOptions);
790 auto Buffer = loadFile(Filename);
791 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
792 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
793 std::string OutputName = OutputFilename;
794 if (OutputName.empty()) {
795 OutputName = Filename + ".imports";
796 }
797 OutputName =
798 getThinLTOOutputFile(Path: OutputName, OldPrefix, NewPrefix);
799 ThinGenerator.emitImports(Module&: *TheModule, OutputName, Index&: *Index, File: *Input);
800 }
801 }
802
803 /// Load the combined index from disk, then load every file referenced by
804 /// the index and add them to the generator, finally perform the promotion
805 /// on the files mentioned on the command line (these must match the index
806 /// content).
807 void promote() {
808 if (InputFilenames.size() != 1 && !OutputFilename.empty())
809 report_fatal_error(reason: "Can't handle a single output filename and multiple "
810 "input files, do not provide an output filename and "
811 "the output files will be suffixed from the input "
812 "ones.");
813
814 auto Index = loadCombinedIndex();
815 for (auto &Filename : InputFilenames) {
816 ToolContext Ctx(LibraryOptions);
817 auto Buffer = loadFile(Filename);
818 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
819 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
820
821 ThinGenerator.promote(Module&: *TheModule, Index&: *Index, File: *Input);
822
823 std::string OutputName = OutputFilename;
824 if (OutputName.empty()) {
825 OutputName = Filename + ".thinlto.promoted.bc";
826 }
827 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
828 }
829 }
830
831 /// Load the combined index from disk, then load every file referenced by
832 /// the index and add them to the generator, then performs the promotion and
833 /// cross module importing on the files mentioned on the command line
834 /// (these must match the index content).
835 void import() {
836 if (InputFilenames.size() != 1 && !OutputFilename.empty())
837 report_fatal_error(reason: "Can't handle a single output filename and multiple "
838 "input files, do not provide an output filename and "
839 "the output files will be suffixed from the input "
840 "ones.");
841
842 auto Index = loadCombinedIndex();
843 auto InputBuffers = loadAllFilesForIndex(Index: *Index);
844 for (auto &MemBuffer : InputBuffers)
845 ThinGenerator.addModule(Identifier: MemBuffer->getBufferIdentifier(),
846 Data: MemBuffer->getBuffer());
847
848 for (auto &Filename : InputFilenames) {
849 ToolContext Ctx(LibraryOptions);
850 auto Buffer = loadFile(Filename);
851 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
852 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
853
854 ThinGenerator.crossModuleImport(Module&: *TheModule, Index&: *Index, File: *Input);
855
856 std::string OutputName = OutputFilename;
857 if (OutputName.empty()) {
858 OutputName = Filename + ".thinlto.imported.bc";
859 }
860 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
861 }
862 }
863
864 void internalize() {
865 if (InputFilenames.size() != 1 && !OutputFilename.empty())
866 report_fatal_error(reason: "Can't handle a single output filename and multiple "
867 "input files, do not provide an output filename and "
868 "the output files will be suffixed from the input "
869 "ones.");
870
871 if (ExportedSymbols.empty())
872 errs() << "Warning: -internalize will not perform without "
873 "-exported-symbol\n";
874
875 auto Index = loadCombinedIndex();
876 auto InputBuffers = loadAllFilesForIndex(Index: *Index);
877 for (auto &MemBuffer : InputBuffers)
878 ThinGenerator.addModule(Identifier: MemBuffer->getBufferIdentifier(),
879 Data: MemBuffer->getBuffer());
880
881 for (auto &Filename : InputFilenames) {
882 ToolContext Ctx(LibraryOptions);
883 auto Buffer = loadFile(Filename);
884 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
885 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
886
887 ThinGenerator.internalize(Module&: *TheModule, Index&: *Index, File: *Input);
888
889 std::string OutputName = OutputFilename;
890 if (OutputName.empty()) {
891 OutputName = Filename + ".thinlto.internalized.bc";
892 }
893 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
894 }
895 }
896
897 void optimize() {
898 if (InputFilenames.size() != 1 && !OutputFilename.empty())
899 report_fatal_error(reason: "Can't handle a single output filename and multiple "
900 "input files, do not provide an output filename and "
901 "the output files will be suffixed from the input "
902 "ones.");
903 if (!ThinLTOIndex.empty())
904 errs() << "Warning: -thinlto-index ignored for optimize stage";
905
906 for (auto &Filename : InputFilenames) {
907 ToolContext Ctx(LibraryOptions);
908 auto Buffer = loadFile(Filename);
909 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
910 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
911
912 ThinGenerator.optimize(Module&: *TheModule);
913
914 std::string OutputName = OutputFilename;
915 if (OutputName.empty()) {
916 OutputName = Filename + ".thinlto.imported.bc";
917 }
918 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
919 }
920 }
921
922 void codegen() {
923 if (InputFilenames.size() != 1 && !OutputFilename.empty())
924 report_fatal_error(reason: "Can't handle a single output filename and multiple "
925 "input files, do not provide an output filename and "
926 "the output files will be suffixed from the input "
927 "ones.");
928 if (!ThinLTOIndex.empty())
929 errs() << "Warning: -thinlto-index ignored for codegen stage";
930
931 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
932 for (auto &Filename : InputFilenames) {
933 LLVMContext Ctx;
934 auto InputOrErr = MemoryBuffer::getFile(Filename);
935 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
936 InputBuffers.push_back(x: std::move(*InputOrErr));
937 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
938 }
939 ThinGenerator.setCodeGenOnly(true);
940 ThinGenerator.run();
941 for (auto BinName :
942 zip(t&: ThinGenerator.getProducedBinaries(), u&: InputFilenames)) {
943 std::string OutputName = OutputFilename;
944 if (OutputName.empty())
945 OutputName = std::get<1>(t&: BinName) + ".thinlto.o";
946 else if (OutputName == "-") {
947 outs() << std::get<0>(t&: BinName)->getBuffer();
948 return;
949 }
950
951 std::error_code EC;
952 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
953 error(EC, Prefix: "error opening the file '" + OutputName + "'");
954 OS << std::get<0>(t&: BinName)->getBuffer();
955 }
956 }
957
958 /// Full ThinLTO process
959 void runAll() {
960 if (!OutputFilename.empty())
961 report_fatal_error(reason: "Do not provide an output filename for ThinLTO "
962 " processing, the output files will be suffixed from "
963 "the input ones.");
964
965 if (!ThinLTOIndex.empty())
966 errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
967
968 LLVMContext Ctx;
969 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
970 for (unsigned i = 0; i < InputFilenames.size(); ++i) {
971 auto &Filename = InputFilenames[i];
972 std::string CurrentActivity = "loading file '" + Filename + "'";
973 auto InputOrErr = MemoryBuffer::getFile(Filename);
974 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
975 InputBuffers.push_back(x: std::move(*InputOrErr));
976 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
977 }
978
979 if (!ThinLTOSaveTempsPrefix.empty())
980 ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
981
982 if (!ThinLTOGeneratedObjectsDir.empty()) {
983 ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
984 ThinGenerator.run();
985 return;
986 }
987
988 ThinGenerator.run();
989
990 auto &Binaries = ThinGenerator.getProducedBinaries();
991 if (Binaries.size() != InputFilenames.size())
992 report_fatal_error(reason: "Number of output objects does not match the number "
993 "of inputs");
994
995 for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
996 auto OutputName = InputFilenames[BufID] + ".thinlto.o";
997 std::error_code EC;
998 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
999 error(EC, Prefix: "error opening the file '" + OutputName + "'");
1000 OS << Binaries[BufID]->getBuffer();
1001 }
1002 }
1003
1004 /// Load the combined index from disk, then load every file referenced by
1005};
1006
1007} // end namespace thinlto
1008
1009int main(int argc, char **argv) {
1010 InitLLVM X(argc, argv);
1011 cl::HideUnrelatedOptions(Categories: {&LTOCategory, &getColorCategory()});
1012 cl::LibraryOptionsContext LibraryOptions;
1013 cl::parseCommandLineOptions(Context&: LibraryOptions, Args: ArrayRef(argv, argc),
1014 Overview: "llvm LTO linker\n");
1015
1016 if (OptLevel < '0' || OptLevel > '3')
1017 error(Msg: "optimization level must be between 0 and 3");
1018
1019 // Initialize the configured targets.
1020 InitializeAllTargets();
1021 InitializeAllTargetMCs();
1022 InitializeAllAsmPrinters();
1023 InitializeAllAsmParsers();
1024
1025 // set up the TargetOptions for the machine
1026 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
1027
1028 if (ListSymbolsOnly || QueryHasCtorDtor) {
1029 testLTOModule(Options);
1030 return 0;
1031 }
1032
1033 if (ListDependentLibrariesOnly) {
1034 listDependentLibraries();
1035 return 0;
1036 }
1037
1038 if (IndexStats) {
1039 printIndexStats();
1040 return 0;
1041 }
1042
1043 if (CheckHasObjC) {
1044 for (auto &Filename : InputFilenames) {
1045 ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +
1046 Filename + "': ");
1047 std::unique_ptr<MemoryBuffer> BufferOrErr =
1048 ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFile(Filename)));
1049 auto Buffer = std::move(BufferOrErr.get());
1050 if (ExitOnErr(isBitcodeContainingObjCCategory(Buffer: *Buffer)))
1051 outs() << "Bitcode " << Filename << " contains ObjC\n";
1052 else
1053 outs() << "Bitcode " << Filename << " does not contain ObjC\n";
1054 }
1055 return 0;
1056 }
1057
1058 if (PrintMachOCPUOnly) {
1059 printMachOCPUOnly();
1060 return 0;
1061 }
1062
1063 if (ThinLTOMode.getNumOccurrences()) {
1064 if (ThinLTOMode.getNumOccurrences() > 1)
1065 report_fatal_error(reason: "You can't specify more than one -thinlto-action");
1066 thinlto::ThinLTOProcessing ThinLTOProcessor(LibraryOptions, Options);
1067 ThinLTOProcessor.run();
1068 return 0;
1069 }
1070
1071 if (ThinLTO) {
1072 createCombinedModuleSummaryIndex();
1073 return 0;
1074 }
1075
1076 unsigned BaseArg = 0;
1077
1078 ToolContext Context(LibraryOptions);
1079 Context.setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
1080 RespectFilters: true);
1081
1082 LTOCodeGenerator CodeGen(Context);
1083 CodeGen.setDisableVerify(DisableVerify);
1084
1085 if (UseDiagnosticHandler)
1086 CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
1087
1088 CodeGen.setCodePICModel(codegen::getExplicitRelocModel());
1089 CodeGen.setFreestanding(EnableFreestanding);
1090 CodeGen.setDebugPassManager(DebugPassManager);
1091
1092 CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
1093 CodeGen.setTargetOptions(Options);
1094 CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
1095
1096 StringSet<MallocAllocator> DSOSymbolsSet(llvm::from_range, DSOSymbols);
1097
1098 std::vector<std::string> KeptDSOSyms;
1099
1100 for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
1101 CurrentActivity = "loading file '" + InputFilenames[i] + "'";
1102 ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
1103 LTOModule::createFromFile(Context, path: InputFilenames[i], options: Options);
1104 std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
1105 CurrentActivity = "";
1106
1107 unsigned NumSyms = Module->getSymbolCount();
1108 for (unsigned I = 0; I < NumSyms; ++I) {
1109 StringRef Name = Module->getSymbolName(index: I);
1110 if (!DSOSymbolsSet.count(Key: Name))
1111 continue;
1112 lto_symbol_attributes Attrs = Module->getSymbolAttributes(index: I);
1113 unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
1114 if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
1115 KeptDSOSyms.push_back(x: std::string(Name));
1116 }
1117
1118 // We use the first input module as the destination module when
1119 // SetMergedModule is true.
1120 if (SetMergedModule && i == BaseArg) {
1121 // Transfer ownership to the code generator.
1122 CodeGen.setModule(std::move(Module));
1123 } else if (!CodeGen.addModule(Module.get())) {
1124 // Print a message here so that we know addModule() did not abort.
1125 error(Msg: "error adding file '" + InputFilenames[i] + "'");
1126 }
1127 }
1128
1129 // Add all the exported symbols to the table of symbols to preserve.
1130 for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
1131 CodeGen.addMustPreserveSymbol(Sym: ExportedSymbols[i]);
1132
1133 // Add all the dso symbols to the table of symbols to expose.
1134 for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
1135 CodeGen.addMustPreserveSymbol(Sym: KeptDSOSyms[i]);
1136
1137 // Set cpu and attrs strings for the default target/subtarget.
1138 CodeGen.setCpu(codegen::getMCPU());
1139
1140 CodeGen.setOptLevel(OptLevel - '0');
1141 CodeGen.setAttrs(codegen::getMAttrs());
1142
1143 if (auto FT = codegen::getExplicitFileType())
1144 CodeGen.setFileType(*FT);
1145
1146 if (!OutputFilename.empty()) {
1147 if (LTOSaveBeforeOpt)
1148 CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");
1149
1150 if (SaveLinkedModuleFile) {
1151 std::string ModuleFilename = OutputFilename;
1152 ModuleFilename += ".linked.bc";
1153
1154 if (!CodeGen.writeMergedModules(Path: ModuleFilename))
1155 error(Msg: "writing linked module failed.");
1156 }
1157
1158 if (!CodeGen.optimize()) {
1159 // Diagnostic messages should have been printed by the handler.
1160 error(Msg: "error optimizing the code");
1161 }
1162
1163 if (SaveModuleFile) {
1164 std::string ModuleFilename = OutputFilename;
1165 ModuleFilename += ".merged.bc";
1166
1167 if (!CodeGen.writeMergedModules(Path: ModuleFilename))
1168 error(Msg: "writing merged module failed.");
1169 }
1170
1171 auto AddStream =
1172 [&](size_t Task,
1173 const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
1174 std::string PartFilename = OutputFilename;
1175 if (Parallelism != 1)
1176 PartFilename += "." + utostr(X: Task);
1177
1178 std::error_code EC;
1179 auto S =
1180 std::make_unique<raw_fd_ostream>(args&: PartFilename, args&: EC, args: sys::fs::OF_None);
1181 if (EC)
1182 error(Msg: "error opening the file '" + PartFilename + "': " + EC.message());
1183 return std::make_unique<CachedFileStream>(args: std::move(S));
1184 };
1185
1186 if (!CodeGen.compileOptimized(AddStream, ParallelismLevel: Parallelism))
1187 // Diagnostic messages should have been printed by the handler.
1188 error(Msg: "error compiling the code");
1189
1190 } else {
1191 if (Parallelism != 1)
1192 error(Msg: "-j must be specified together with -o");
1193
1194 if (SaveModuleFile)
1195 error(Msg: ": -save-merged-module must be specified with -o");
1196
1197 const char *OutputName = nullptr;
1198 if (!CodeGen.compile_to_file(Name: &OutputName))
1199 error(Msg: "error compiling the code");
1200 // Diagnostic messages should have been printed by the handler.
1201
1202 outs() << "Wrote native object file '" << OutputName << "'\n";
1203 }
1204
1205 return 0;
1206}
1207