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/MemoryBuffer.h"
44#include "llvm/Support/Path.h"
45#include "llvm/Support/SourceMgr.h"
46#include "llvm/Support/TargetSelect.h"
47#include "llvm/Support/ToolOutputFile.h"
48#include "llvm/Support/raw_ostream.h"
49#include "llvm/Support/WithColor.h"
50#include "llvm/Target/TargetOptions.h"
51#include <algorithm>
52#include <cassert>
53#include <cstdint>
54#include <cstdlib>
55#include <map>
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
112cl::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
267static cl::opt<bool> TryUseNewDbgInfoFormat(
268 "try-experimental-debuginfo-iterators",
269 cl::desc("Enable debuginfo iterator positions, if they're built in"),
270 cl::init(Val: false), cl::Hidden);
271
272extern cl::opt<bool> UseNewDbgInfoFormat;
273extern cl::opt<cl::boolOrDefault> LoadBitcodeIntoNewDbgInfoFormat;
274extern cl::opt<cl::boolOrDefault> PreserveInputDbgFormat;
275
276namespace {
277
278struct ModuleInfo {
279 BitVector CanBeHidden;
280};
281
282} // end anonymous namespace
283
284static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
285 const char *Msg, void *) {
286 errs() << "llvm-lto: ";
287 switch (Severity) {
288 case LTO_DS_NOTE:
289 errs() << "note: ";
290 break;
291 case LTO_DS_REMARK:
292 errs() << "remark: ";
293 break;
294 case LTO_DS_ERROR:
295 errs() << "error: ";
296 break;
297 case LTO_DS_WARNING:
298 errs() << "warning: ";
299 break;
300 }
301 errs() << Msg << "\n";
302}
303
304static std::string CurrentActivity;
305
306namespace {
307 struct LLVMLTODiagnosticHandler : public DiagnosticHandler {
308 bool handleDiagnostics(const DiagnosticInfo &DI) override {
309 raw_ostream &OS = errs();
310 OS << "llvm-lto: ";
311 switch (DI.getSeverity()) {
312 case DS_Error:
313 OS << "error";
314 break;
315 case DS_Warning:
316 OS << "warning";
317 break;
318 case DS_Remark:
319 OS << "remark";
320 break;
321 case DS_Note:
322 OS << "note";
323 break;
324 }
325 if (!CurrentActivity.empty())
326 OS << ' ' << CurrentActivity;
327 OS << ": ";
328
329 DiagnosticPrinterRawOStream DP(OS);
330 DI.print(DP);
331 OS << '\n';
332
333 if (DI.getSeverity() == DS_Error)
334 exit(status: 1);
335 return true;
336 }
337 };
338 }
339
340static void error(const Twine &Msg) {
341 errs() << "llvm-lto: " << Msg << '\n';
342 exit(status: 1);
343}
344
345static void error(std::error_code EC, const Twine &Prefix) {
346 if (EC)
347 error(Msg: Prefix + ": " + EC.message());
348}
349
350template <typename T>
351static void error(const ErrorOr<T> &V, const Twine &Prefix) {
352 error(V.getError(), Prefix);
353}
354
355static void maybeVerifyModule(const Module &Mod) {
356 if (!DisableVerify && verifyModule(M: Mod, OS: &errs()))
357 error(Msg: "Broken Module");
358}
359
360static std::unique_ptr<LTOModule>
361getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
362 const TargetOptions &Options) {
363 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
364 MemoryBuffer::getFile(Filename: Path);
365 error(V: BufferOrErr, Prefix: "error loading file '" + Path + "'");
366 Buffer = std::move(BufferOrErr.get());
367 CurrentActivity = ("loading file '" + Path + "'").str();
368 std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
369 Context->setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
370 RespectFilters: true);
371 ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
372 Context: std::move(Context), mem: Buffer->getBufferStart(), length: Buffer->getBufferSize(),
373 options: Options, path: Path);
374 CurrentActivity = "";
375 maybeVerifyModule(Mod: (*Ret)->getModule());
376 return std::move(*Ret);
377}
378
379/// Print some statistics on the index for each input files.
380static void printIndexStats() {
381 for (auto &Filename : InputFilenames) {
382 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
383 std::unique_ptr<ModuleSummaryIndex> Index =
384 ExitOnErr(getModuleSummaryIndexForFile(Path: Filename));
385 // Skip files without a module summary.
386 if (!Index)
387 report_fatal_error(reason: Twine(Filename) + " does not contain an index");
388
389 unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
390 for (auto &Summaries : *Index) {
391 for (auto &Summary : Summaries.second.SummaryList) {
392 Refs += Summary->refs().size();
393 if (auto *FuncSummary = dyn_cast<FunctionSummary>(Val: Summary.get())) {
394 Functions++;
395 Calls += FuncSummary->calls().size();
396 } else if (isa<AliasSummary>(Val: Summary.get()))
397 Alias++;
398 else
399 Globals++;
400 }
401 }
402 outs() << "Index " << Filename << " contains "
403 << (Alias + Globals + Functions) << " nodes (" << Functions
404 << " functions, " << Alias << " alias, " << Globals
405 << " globals) and " << (Calls + Refs) << " edges (" << Refs
406 << " refs and " << Calls << " calls)\n";
407 }
408}
409
410/// Load each IR file and dump certain information based on active flags.
411///
412/// The main point here is to provide lit-testable coverage for the LTOModule
413/// functionality that's exposed by the C API. Moreover, this provides testing
414/// coverage for modules that have been created in their own contexts.
415static void testLTOModule(const TargetOptions &Options) {
416 for (auto &Filename : InputFilenames) {
417 std::unique_ptr<MemoryBuffer> Buffer;
418 std::unique_ptr<LTOModule> Module =
419 getLocalLTOModule(Path: Filename, Buffer, Options);
420
421 if (ListSymbolsOnly) {
422 // List the symbols.
423 outs() << Filename << ":\n";
424 for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
425 outs() << Module->getSymbolName(index: I) << "\n";
426 }
427 if (QueryHasCtorDtor)
428 outs() << Filename
429 << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")
430 << "\n";
431 }
432}
433
434static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
435 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
436 "': ");
437 return ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFileOrSTDIN(Filename)));
438}
439
440static void listDependentLibraries() {
441 for (auto &Filename : InputFilenames) {
442 auto Buffer = loadFile(Filename);
443 std::string E;
444 std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
445 buffer: Buffer->getBufferStart(), buffer_size: Buffer->getBufferSize(), path: Filename.c_str(),
446 out_error&: E));
447 if (!Input)
448 error(Msg: E);
449
450 // List the dependent libraries.
451 outs() << Filename << ":\n";
452 for (size_t I = 0, C = LTOModule::getDependentLibraryCount(input: Input.get());
453 I != C; ++I) {
454 size_t L = 0;
455 const char *S = LTOModule::getDependentLibrary(input: Input.get(), index: I, size: &L);
456 assert(S);
457 outs() << StringRef(S, L) << "\n";
458 }
459 }
460}
461
462static void printMachOCPUOnly() {
463 LLVMContext Context;
464 Context.setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
465 RespectFilters: true);
466 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
467 for (auto &Filename : InputFilenames) {
468 ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
469 LTOModule::createFromFile(Context, path: Filename, options: Options);
470 if (!ModuleOrErr)
471 error(V: ModuleOrErr, Prefix: "llvm-lto: ");
472
473 Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();
474 Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();
475 if (!CPUType)
476 error(Msg: "Error while printing mach-o cputype: " +
477 toString(E: CPUType.takeError()));
478 if (!CPUSubType)
479 error(Msg: "Error while printing mach-o cpusubtype: " +
480 toString(E: CPUSubType.takeError()));
481 outs() << llvm::format(Fmt: "%s:\ncputype: %u\ncpusubtype: %u\n",
482 Vals: Filename.c_str(), Vals: *CPUType, Vals: *CPUSubType);
483 }
484}
485
486/// Create a combined index file from the input IR files and write it.
487///
488/// This is meant to enable testing of ThinLTO combined index generation,
489/// currently available via the gold plugin via -thinlto.
490static void createCombinedModuleSummaryIndex() {
491 ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
492 for (auto &Filename : InputFilenames) {
493 ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
494 std::unique_ptr<MemoryBuffer> MB =
495 ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFileOrSTDIN(Filename)));
496 ExitOnErr(readModuleSummaryIndex(Buffer: *MB, CombinedIndex));
497 }
498 // In order to use this index for testing, specifically import testing, we
499 // need to update any indirect call edges created from SamplePGO, so that they
500 // point to the correct GUIDs.
501 updateIndirectCalls(Index&: CombinedIndex);
502 std::error_code EC;
503 assert(!OutputFilename.empty());
504 raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
505 sys::fs::OpenFlags::OF_None);
506 error(EC, Prefix: "error opening the file '" + OutputFilename + ".thinlto.bc'");
507 writeIndexToFile(Index: CombinedIndex, Out&: OS);
508 OS.close();
509}
510
511/// Parse the thinlto_prefix_replace option into the \p OldPrefix and
512/// \p NewPrefix strings, if it was specified.
513static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
514 std::string &NewPrefix) {
515 assert(ThinLTOPrefixReplace.empty() ||
516 ThinLTOPrefixReplace.find(';') != StringRef::npos);
517 StringRef PrefixReplace = ThinLTOPrefixReplace;
518 std::pair<StringRef, StringRef> Split = PrefixReplace.split(Separator: ";");
519 OldPrefix = Split.first.str();
520 NewPrefix = Split.second.str();
521}
522
523/// Given the original \p Path to an output file, replace any path
524/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
525/// resulting directory if it does not yet exist.
526static std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix,
527 StringRef NewPrefix) {
528 if (OldPrefix.empty() && NewPrefix.empty())
529 return std::string(Path);
530 SmallString<128> NewPath(Path);
531 llvm::sys::path::replace_path_prefix(Path&: NewPath, OldPrefix, NewPrefix);
532 StringRef ParentPath = llvm::sys::path::parent_path(path: NewPath.str());
533 if (!ParentPath.empty()) {
534 // Make sure the new directory exists, creating it if necessary.
535 if (std::error_code EC = llvm::sys::fs::create_directories(path: ParentPath))
536 error(EC, Prefix: "error creating the directory '" + ParentPath + "'");
537 }
538 return std::string(NewPath);
539}
540
541namespace thinlto {
542
543std::vector<std::unique_ptr<MemoryBuffer>>
544loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
545 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
546
547 for (auto &ModPath : Index.modulePaths()) {
548 const auto &Filename = ModPath.first();
549 std::string CurrentActivity = ("loading file '" + Filename + "'").str();
550 auto InputOrErr = MemoryBuffer::getFile(Filename);
551 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
552 InputBuffers.push_back(x: std::move(*InputOrErr));
553 }
554 return InputBuffers;
555}
556
557std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
558 if (ThinLTOIndex.empty())
559 report_fatal_error(reason: "Missing -thinlto-index for ThinLTO promotion stage");
560 ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +
561 "': ");
562 return ExitOnErr(getModuleSummaryIndexForFile(Path: ThinLTOIndex));
563}
564
565static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
566 ExitOnError ExitOnErr("llvm-lto: error loading input '" +
567 Buffer.getBufferIdentifier().str() + "': ");
568 return ExitOnErr(lto::InputFile::create(Object: Buffer));
569}
570
571static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
572 LLVMContext &CTX) {
573 auto &Mod = File.getSingleBitcodeModule();
574 auto ModuleOrErr = Mod.parseModule(Context&: CTX);
575 if (!ModuleOrErr) {
576 handleAllErrors(E: ModuleOrErr.takeError(), Handlers: [&](ErrorInfoBase &EIB) {
577 SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
578 SourceMgr::DK_Error, EIB.message());
579 Err.print(ProgName: "llvm-lto", S&: errs());
580 });
581 report_fatal_error(reason: "Can't load module, abort.");
582 }
583 maybeVerifyModule(Mod: **ModuleOrErr);
584 if (ThinLTOModuleId.getNumOccurrences()) {
585 if (InputFilenames.size() != 1)
586 report_fatal_error(reason: "Can't override the module id for multiple files");
587 (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
588 }
589 return std::move(*ModuleOrErr);
590}
591
592static void writeModuleToFile(Module &TheModule, StringRef Filename) {
593 std::error_code EC;
594 raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);
595 error(EC, Prefix: "error opening the file '" + Filename + "'");
596 maybeVerifyModule(Mod: TheModule);
597 WriteBitcodeToFile(M: TheModule, Out&: OS, /* ShouldPreserveUseListOrder */ true);
598}
599
600class ThinLTOProcessing {
601public:
602 ThinLTOCodeGenerator ThinGenerator;
603
604 ThinLTOProcessing(const TargetOptions &Options) {
605 ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());
606 ThinGenerator.setTargetOptions(Options);
607 ThinGenerator.setCacheDir(ThinLTOCacheDir);
608 ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);
609 ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
610 ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
611 ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
612 ThinGenerator.setFreestanding(EnableFreestanding);
613 ThinGenerator.setDebugPassManager(DebugPassManager);
614
615 // Add all the exported symbols to the table of symbols to preserve.
616 for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
617 ThinGenerator.preserveSymbol(Name: ExportedSymbols[i]);
618 }
619
620 void run() {
621 switch (ThinLTOMode) {
622 case THINLINK:
623 return thinLink();
624 case THINDISTRIBUTE:
625 return distributedIndexes();
626 case THINEMITIMPORTS:
627 return emitImports();
628 case THINPROMOTE:
629 return promote();
630 case THINIMPORT:
631 return import();
632 case THININTERNALIZE:
633 return internalize();
634 case THINOPT:
635 return optimize();
636 case THINCODEGEN:
637 return codegen();
638 case THINALL:
639 return runAll();
640 }
641 }
642
643private:
644 /// Load the input files, create the combined index, and write it out.
645 void thinLink() {
646 // Perform "ThinLink": just produce the index
647 if (OutputFilename.empty())
648 report_fatal_error(
649 reason: "OutputFilename is necessary to store the combined index.\n");
650
651 LLVMContext Ctx;
652 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
653 for (unsigned i = 0; i < InputFilenames.size(); ++i) {
654 auto &Filename = InputFilenames[i];
655 std::string CurrentActivity = "loading file '" + Filename + "'";
656 auto InputOrErr = MemoryBuffer::getFile(Filename);
657 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
658 InputBuffers.push_back(x: std::move(*InputOrErr));
659 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
660 }
661
662 auto CombinedIndex = ThinGenerator.linkCombinedIndex();
663 if (!CombinedIndex)
664 report_fatal_error(reason: "ThinLink didn't create an index");
665 std::error_code EC;
666 raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
667 error(EC, Prefix: "error opening the file '" + OutputFilename + "'");
668 writeIndexToFile(Index: *CombinedIndex, Out&: OS);
669 }
670
671 /// Load the combined index from disk, then compute and generate
672 /// individual index files suitable for ThinLTO distributed backend builds
673 /// on the files mentioned on the command line (these must match the index
674 /// content).
675 void distributedIndexes() {
676 if (InputFilenames.size() != 1 && !OutputFilename.empty())
677 report_fatal_error(reason: "Can't handle a single output filename and multiple "
678 "input files, do not provide an output filename and "
679 "the output files will be suffixed from the input "
680 "ones.");
681
682 std::string OldPrefix, NewPrefix;
683 getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
684
685 auto Index = loadCombinedIndex();
686 for (auto &Filename : InputFilenames) {
687 LLVMContext Ctx;
688 auto Buffer = loadFile(Filename);
689 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
690 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
691
692 // Build a map of module to the GUIDs and summary objects that should
693 // be written to its index.
694 std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
695 GVSummaryPtrSet DecSummaries;
696 ThinGenerator.gatherImportedSummariesForModule(
697 Module&: *TheModule, Index&: *Index, ModuleToSummariesForIndex, DecSummaries, File: *Input);
698
699 std::string OutputName = OutputFilename;
700 if (OutputName.empty()) {
701 OutputName = Filename + ".thinlto.bc";
702 }
703 OutputName = getThinLTOOutputFile(Path: OutputName, OldPrefix, NewPrefix);
704 std::error_code EC;
705 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
706 error(EC, Prefix: "error opening the file '" + OutputName + "'");
707 writeIndexToFile(Index: *Index, Out&: OS, ModuleToSummariesForIndex: &ModuleToSummariesForIndex, DecSummaries: &DecSummaries);
708 }
709 }
710
711 /// Load the combined index from disk, compute the imports, and emit
712 /// the import file lists for each module to disk.
713 void emitImports() {
714 if (InputFilenames.size() != 1 && !OutputFilename.empty())
715 report_fatal_error(reason: "Can't handle a single output filename and multiple "
716 "input files, do not provide an output filename and "
717 "the output files will be suffixed from the input "
718 "ones.");
719
720 std::string OldPrefix, NewPrefix;
721 getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
722
723 auto Index = loadCombinedIndex();
724 for (auto &Filename : InputFilenames) {
725 LLVMContext Ctx;
726 auto Buffer = loadFile(Filename);
727 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
728 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
729 std::string OutputName = OutputFilename;
730 if (OutputName.empty()) {
731 OutputName = Filename + ".imports";
732 }
733 OutputName =
734 getThinLTOOutputFile(Path: OutputName, OldPrefix, NewPrefix);
735 ThinGenerator.emitImports(Module&: *TheModule, OutputName, Index&: *Index, File: *Input);
736 }
737 }
738
739 /// Load the combined index from disk, then load every file referenced by
740 /// the index and add them to the generator, finally perform the promotion
741 /// on the files mentioned on the command line (these must match the index
742 /// content).
743 void promote() {
744 if (InputFilenames.size() != 1 && !OutputFilename.empty())
745 report_fatal_error(reason: "Can't handle a single output filename and multiple "
746 "input files, do not provide an output filename and "
747 "the output files will be suffixed from the input "
748 "ones.");
749
750 auto Index = loadCombinedIndex();
751 for (auto &Filename : InputFilenames) {
752 LLVMContext Ctx;
753 auto Buffer = loadFile(Filename);
754 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
755 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
756
757 ThinGenerator.promote(Module&: *TheModule, Index&: *Index, File: *Input);
758
759 std::string OutputName = OutputFilename;
760 if (OutputName.empty()) {
761 OutputName = Filename + ".thinlto.promoted.bc";
762 }
763 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
764 }
765 }
766
767 /// Load the combined index from disk, then load every file referenced by
768 /// the index and add them to the generator, then performs the promotion and
769 /// cross module importing on the files mentioned on the command line
770 /// (these must match the index content).
771 void import() {
772 if (InputFilenames.size() != 1 && !OutputFilename.empty())
773 report_fatal_error(reason: "Can't handle a single output filename and multiple "
774 "input files, do not provide an output filename and "
775 "the output files will be suffixed from the input "
776 "ones.");
777
778 auto Index = loadCombinedIndex();
779 auto InputBuffers = loadAllFilesForIndex(Index: *Index);
780 for (auto &MemBuffer : InputBuffers)
781 ThinGenerator.addModule(Identifier: MemBuffer->getBufferIdentifier(),
782 Data: MemBuffer->getBuffer());
783
784 for (auto &Filename : InputFilenames) {
785 LLVMContext Ctx;
786 auto Buffer = loadFile(Filename);
787 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
788 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
789
790 ThinGenerator.crossModuleImport(Module&: *TheModule, Index&: *Index, File: *Input);
791
792 std::string OutputName = OutputFilename;
793 if (OutputName.empty()) {
794 OutputName = Filename + ".thinlto.imported.bc";
795 }
796 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
797 }
798 }
799
800 void internalize() {
801 if (InputFilenames.size() != 1 && !OutputFilename.empty())
802 report_fatal_error(reason: "Can't handle a single output filename and multiple "
803 "input files, do not provide an output filename and "
804 "the output files will be suffixed from the input "
805 "ones.");
806
807 if (ExportedSymbols.empty())
808 errs() << "Warning: -internalize will not perform without "
809 "-exported-symbol\n";
810
811 auto Index = loadCombinedIndex();
812 auto InputBuffers = loadAllFilesForIndex(Index: *Index);
813 for (auto &MemBuffer : InputBuffers)
814 ThinGenerator.addModule(Identifier: MemBuffer->getBufferIdentifier(),
815 Data: MemBuffer->getBuffer());
816
817 for (auto &Filename : InputFilenames) {
818 LLVMContext Ctx;
819 auto Buffer = loadFile(Filename);
820 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
821 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
822
823 ThinGenerator.internalize(Module&: *TheModule, Index&: *Index, File: *Input);
824
825 std::string OutputName = OutputFilename;
826 if (OutputName.empty()) {
827 OutputName = Filename + ".thinlto.internalized.bc";
828 }
829 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
830 }
831 }
832
833 void optimize() {
834 if (InputFilenames.size() != 1 && !OutputFilename.empty())
835 report_fatal_error(reason: "Can't handle a single output filename and multiple "
836 "input files, do not provide an output filename and "
837 "the output files will be suffixed from the input "
838 "ones.");
839 if (!ThinLTOIndex.empty())
840 errs() << "Warning: -thinlto-index ignored for optimize stage";
841
842 for (auto &Filename : InputFilenames) {
843 LLVMContext Ctx;
844 auto Buffer = loadFile(Filename);
845 auto Input = loadInputFile(Buffer: Buffer->getMemBufferRef());
846 auto TheModule = loadModuleFromInput(File&: *Input, CTX&: Ctx);
847
848 ThinGenerator.optimize(Module&: *TheModule);
849
850 std::string OutputName = OutputFilename;
851 if (OutputName.empty()) {
852 OutputName = Filename + ".thinlto.imported.bc";
853 }
854 writeModuleToFile(TheModule&: *TheModule, Filename: OutputName);
855 }
856 }
857
858 void codegen() {
859 if (InputFilenames.size() != 1 && !OutputFilename.empty())
860 report_fatal_error(reason: "Can't handle a single output filename and multiple "
861 "input files, do not provide an output filename and "
862 "the output files will be suffixed from the input "
863 "ones.");
864 if (!ThinLTOIndex.empty())
865 errs() << "Warning: -thinlto-index ignored for codegen stage";
866
867 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
868 for (auto &Filename : InputFilenames) {
869 LLVMContext Ctx;
870 auto InputOrErr = MemoryBuffer::getFile(Filename);
871 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
872 InputBuffers.push_back(x: std::move(*InputOrErr));
873 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
874 }
875 ThinGenerator.setCodeGenOnly(true);
876 ThinGenerator.run();
877 for (auto BinName :
878 zip(t&: ThinGenerator.getProducedBinaries(), u&: InputFilenames)) {
879 std::string OutputName = OutputFilename;
880 if (OutputName.empty())
881 OutputName = std::get<1>(t&: BinName) + ".thinlto.o";
882 else if (OutputName == "-") {
883 outs() << std::get<0>(t&: BinName)->getBuffer();
884 return;
885 }
886
887 std::error_code EC;
888 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
889 error(EC, Prefix: "error opening the file '" + OutputName + "'");
890 OS << std::get<0>(t&: BinName)->getBuffer();
891 }
892 }
893
894 /// Full ThinLTO process
895 void runAll() {
896 if (!OutputFilename.empty())
897 report_fatal_error(reason: "Do not provide an output filename for ThinLTO "
898 " processing, the output files will be suffixed from "
899 "the input ones.");
900
901 if (!ThinLTOIndex.empty())
902 errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
903
904 LLVMContext Ctx;
905 std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
906 for (unsigned i = 0; i < InputFilenames.size(); ++i) {
907 auto &Filename = InputFilenames[i];
908 std::string CurrentActivity = "loading file '" + Filename + "'";
909 auto InputOrErr = MemoryBuffer::getFile(Filename);
910 error(V: InputOrErr, Prefix: "error " + CurrentActivity);
911 InputBuffers.push_back(x: std::move(*InputOrErr));
912 ThinGenerator.addModule(Identifier: Filename, Data: InputBuffers.back()->getBuffer());
913 }
914
915 if (!ThinLTOSaveTempsPrefix.empty())
916 ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
917
918 if (!ThinLTOGeneratedObjectsDir.empty()) {
919 ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
920 ThinGenerator.run();
921 return;
922 }
923
924 ThinGenerator.run();
925
926 auto &Binaries = ThinGenerator.getProducedBinaries();
927 if (Binaries.size() != InputFilenames.size())
928 report_fatal_error(reason: "Number of output objects does not match the number "
929 "of inputs");
930
931 for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
932 auto OutputName = InputFilenames[BufID] + ".thinlto.o";
933 std::error_code EC;
934 raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
935 error(EC, Prefix: "error opening the file '" + OutputName + "'");
936 OS << Binaries[BufID]->getBuffer();
937 }
938 }
939
940 /// Load the combined index from disk, then load every file referenced by
941};
942
943} // end namespace thinlto
944
945int main(int argc, char **argv) {
946 InitLLVM X(argc, argv);
947 cl::HideUnrelatedOptions(Categories: {&LTOCategory, &getColorCategory()});
948 cl::ParseCommandLineOptions(argc, argv, Overview: "llvm LTO linker\n");
949 // Load bitcode into the new debug info format by default.
950 if (LoadBitcodeIntoNewDbgInfoFormat == cl::boolOrDefault::BOU_UNSET)
951 LoadBitcodeIntoNewDbgInfoFormat = cl::boolOrDefault::BOU_TRUE;
952
953 // RemoveDIs debug-info transition: tests may request that we /try/ to use the
954 // new debug-info format.
955 if (TryUseNewDbgInfoFormat) {
956 // Turn the new debug-info format on.
957 UseNewDbgInfoFormat = true;
958 }
959 // Since llvm-lto collects multiple IR modules together, for simplicity's sake
960 // we disable the "PreserveInputDbgFormat" flag to enforce a single debug info
961 // format.
962 PreserveInputDbgFormat = cl::boolOrDefault::BOU_FALSE;
963
964 if (OptLevel < '0' || OptLevel > '3')
965 error(Msg: "optimization level must be between 0 and 3");
966
967 // Initialize the configured targets.
968 InitializeAllTargets();
969 InitializeAllTargetMCs();
970 InitializeAllAsmPrinters();
971 InitializeAllAsmParsers();
972
973 // set up the TargetOptions for the machine
974 TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: Triple());
975
976 if (ListSymbolsOnly || QueryHasCtorDtor) {
977 testLTOModule(Options);
978 return 0;
979 }
980
981 if (ListDependentLibrariesOnly) {
982 listDependentLibraries();
983 return 0;
984 }
985
986 if (IndexStats) {
987 printIndexStats();
988 return 0;
989 }
990
991 if (CheckHasObjC) {
992 for (auto &Filename : InputFilenames) {
993 ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +
994 Filename + "': ");
995 std::unique_ptr<MemoryBuffer> BufferOrErr =
996 ExitOnErr(errorOrToExpected(EO: MemoryBuffer::getFile(Filename)));
997 auto Buffer = std::move(BufferOrErr.get());
998 if (ExitOnErr(isBitcodeContainingObjCCategory(Buffer: *Buffer)))
999 outs() << "Bitcode " << Filename << " contains ObjC\n";
1000 else
1001 outs() << "Bitcode " << Filename << " does not contain ObjC\n";
1002 }
1003 return 0;
1004 }
1005
1006 if (PrintMachOCPUOnly) {
1007 printMachOCPUOnly();
1008 return 0;
1009 }
1010
1011 if (ThinLTOMode.getNumOccurrences()) {
1012 if (ThinLTOMode.getNumOccurrences() > 1)
1013 report_fatal_error(reason: "You can't specify more than one -thinlto-action");
1014 thinlto::ThinLTOProcessing ThinLTOProcessor(Options);
1015 ThinLTOProcessor.run();
1016 return 0;
1017 }
1018
1019 if (ThinLTO) {
1020 createCombinedModuleSummaryIndex();
1021 return 0;
1022 }
1023
1024 unsigned BaseArg = 0;
1025
1026 LLVMContext Context;
1027 Context.setDiagnosticHandler(DH: std::make_unique<LLVMLTODiagnosticHandler>(),
1028 RespectFilters: true);
1029
1030 LTOCodeGenerator CodeGen(Context);
1031 CodeGen.setDisableVerify(DisableVerify);
1032
1033 if (UseDiagnosticHandler)
1034 CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
1035
1036 CodeGen.setCodePICModel(codegen::getExplicitRelocModel());
1037 CodeGen.setFreestanding(EnableFreestanding);
1038 CodeGen.setDebugPassManager(DebugPassManager);
1039
1040 CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
1041 CodeGen.setTargetOptions(Options);
1042 CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
1043
1044 StringSet<MallocAllocator> DSOSymbolsSet;
1045 for (unsigned i = 0; i < DSOSymbols.size(); ++i)
1046 DSOSymbolsSet.insert(key: DSOSymbols[i]);
1047
1048 std::vector<std::string> KeptDSOSyms;
1049
1050 for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
1051 CurrentActivity = "loading file '" + InputFilenames[i] + "'";
1052 ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
1053 LTOModule::createFromFile(Context, path: InputFilenames[i], options: Options);
1054 std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
1055 CurrentActivity = "";
1056
1057 unsigned NumSyms = Module->getSymbolCount();
1058 for (unsigned I = 0; I < NumSyms; ++I) {
1059 StringRef Name = Module->getSymbolName(index: I);
1060 if (!DSOSymbolsSet.count(Key: Name))
1061 continue;
1062 lto_symbol_attributes Attrs = Module->getSymbolAttributes(index: I);
1063 unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
1064 if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
1065 KeptDSOSyms.push_back(x: std::string(Name));
1066 }
1067
1068 // We use the first input module as the destination module when
1069 // SetMergedModule is true.
1070 if (SetMergedModule && i == BaseArg) {
1071 // Transfer ownership to the code generator.
1072 CodeGen.setModule(std::move(Module));
1073 } else if (!CodeGen.addModule(Module.get())) {
1074 // Print a message here so that we know addModule() did not abort.
1075 error(Msg: "error adding file '" + InputFilenames[i] + "'");
1076 }
1077 }
1078
1079 // Add all the exported symbols to the table of symbols to preserve.
1080 for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
1081 CodeGen.addMustPreserveSymbol(Sym: ExportedSymbols[i]);
1082
1083 // Add all the dso symbols to the table of symbols to expose.
1084 for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
1085 CodeGen.addMustPreserveSymbol(Sym: KeptDSOSyms[i]);
1086
1087 // Set cpu and attrs strings for the default target/subtarget.
1088 CodeGen.setCpu(codegen::getMCPU());
1089
1090 CodeGen.setOptLevel(OptLevel - '0');
1091 CodeGen.setAttrs(codegen::getMAttrs());
1092
1093 if (auto FT = codegen::getExplicitFileType())
1094 CodeGen.setFileType(*FT);
1095
1096 if (!OutputFilename.empty()) {
1097 if (LTOSaveBeforeOpt)
1098 CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");
1099
1100 if (SaveLinkedModuleFile) {
1101 std::string ModuleFilename = OutputFilename;
1102 ModuleFilename += ".linked.bc";
1103 std::string ErrMsg;
1104
1105 if (!CodeGen.writeMergedModules(Path: ModuleFilename))
1106 error(Msg: "writing linked module failed.");
1107 }
1108
1109 if (!CodeGen.optimize()) {
1110 // Diagnostic messages should have been printed by the handler.
1111 error(Msg: "error optimizing the code");
1112 }
1113
1114 if (SaveModuleFile) {
1115 std::string ModuleFilename = OutputFilename;
1116 ModuleFilename += ".merged.bc";
1117 std::string ErrMsg;
1118
1119 if (!CodeGen.writeMergedModules(Path: ModuleFilename))
1120 error(Msg: "writing merged module failed.");
1121 }
1122
1123 auto AddStream =
1124 [&](size_t Task,
1125 const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
1126 std::string PartFilename = OutputFilename;
1127 if (Parallelism != 1)
1128 PartFilename += "." + utostr(X: Task);
1129
1130 std::error_code EC;
1131 auto S =
1132 std::make_unique<raw_fd_ostream>(args&: PartFilename, args&: EC, args: sys::fs::OF_None);
1133 if (EC)
1134 error(Msg: "error opening the file '" + PartFilename + "': " + EC.message());
1135 return std::make_unique<CachedFileStream>(args: std::move(S));
1136 };
1137
1138 if (!CodeGen.compileOptimized(AddStream, ParallelismLevel: Parallelism))
1139 // Diagnostic messages should have been printed by the handler.
1140 error(Msg: "error compiling the code");
1141
1142 } else {
1143 if (Parallelism != 1)
1144 error(Msg: "-j must be specified together with -o");
1145
1146 if (SaveModuleFile)
1147 error(Msg: ": -save-merged-module must be specified with -o");
1148
1149 const char *OutputName = nullptr;
1150 if (!CodeGen.compile_to_file(Name: &OutputName))
1151 error(Msg: "error compiling the code");
1152 // Diagnostic messages should have been printed by the handler.
1153
1154 outs() << "Wrote native object file '" << OutputName << "'\n";
1155 }
1156
1157 return 0;
1158}
1159