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