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