1 //===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
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
7 //===----------------------------------------------------------------------===//
9 // This program takes in a list of bitcode files, links them and performs
10 // link-time optimization according to the provided symbol resolutions using the
11 // resolution-based LTO interface, and outputs one or more object files.
13 // This program is intended to eventually replace llvm-lto which uses the legacy
16 //===----------------------------------------------------------------------===//
18 #include "llvm/Bitcode/BitcodeReader.h"
19 #include "llvm/CodeGen/CommandFlags.h"
20 #include "llvm/IR/DiagnosticPrinter.h"
21 #include "llvm/LTO/LTO.h"
22 #include "llvm/Passes/PassPlugin.h"
23 #include "llvm/Remarks/HotnessThresholdParser.h"
24 #include "llvm/Support/Caching.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/InitLLVM.h"
28 #include "llvm/Support/PluginLoader.h"
29 #include "llvm/Support/TargetSelect.h"
30 #include "llvm/Support/Threading.h"
36 static codegen::RegisterCodeGenFlags CGF
;
40 cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
42 cl::Prefix
, cl::init('2'));
44 static cl::opt
<char> CGOptLevel(
46 cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"),
49 static cl::list
<std::string
> InputFilenames(cl::Positional
, cl::OneOrMore
,
50 cl::desc("<input bitcode files>"));
52 static cl::opt
<std::string
> OutputFilename("o", cl::Required
,
53 cl::desc("Output filename"),
54 cl::value_desc("filename"));
56 static cl::opt
<std::string
> CacheDir("cache-dir", cl::desc("Cache Directory"),
57 cl::value_desc("directory"));
59 static cl::opt
<std::string
> OptPipeline("opt-pipeline",
60 cl::desc("Optimizer Pipeline"),
61 cl::value_desc("pipeline"));
63 static cl::opt
<std::string
> AAPipeline("aa-pipeline",
64 cl::desc("Alias Analysis Pipeline"),
65 cl::value_desc("aapipeline"));
67 static cl::opt
<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
69 static cl::list
<std::string
> SelectSaveTemps(
71 cl::value_desc("One, or multiple of: "
72 "resolution,preopt,promote,internalize,import,opt,precodegen"
74 cl::desc("Save selected temporary files. Cannot be specified together with "
78 constexpr const char *SaveTempsValues
[] = {
79 "resolution", "preopt", "promote", "internalize",
80 "import", "opt", "precodegen", "combinedindex"};
83 ThinLTODistributedIndexes("thinlto-distributed-indexes",
84 cl::desc("Write out individual index and "
85 "import files for the "
86 "distributed backend case"));
89 ThinLTOEmitIndexes("thinlto-emit-indexes",
90 cl::desc("Write out individual index files via "
94 ThinLTOEmitImports("thinlto-emit-imports",
95 cl::desc("Write out individual imports files via "
96 "InProcessThinLTO. Has no effect unless "
97 "specified with -thinlto-emit-indexes or "
98 "-thinlto-distributed-indexes"));
100 // Default to using all available threads in the system, but using only one
101 // thread per core (no SMT).
102 // Use -thinlto-threads=all to use hardware_concurrency() instead, which means
103 // to use all hardware threads or cores in the system.
104 static cl::opt
<std::string
> Threads("thinlto-threads");
106 static cl::list
<std::string
> SymbolResolutions(
108 cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
109 "where \"resolution\" is a sequence (which may be empty) of the\n"
110 "following characters:\n"
111 " p - prevailing: the linker has chosen this definition of the\n"
113 " l - local: the definition of this symbol is unpreemptable at\n"
114 " runtime and is known to be in this linkage unit\n"
115 " x - externally visible: the definition of this symbol is\n"
116 " visible outside of the LTO unit\n"
117 "A resolution for each symbol must be specified"));
119 static cl::opt
<std::string
> OverrideTriple(
121 cl::desc("Replace target triples in input files with this triple"));
123 static cl::opt
<std::string
> DefaultTriple(
126 "Replace unspecified target triples in input files with this triple"));
128 static cl::opt
<bool> RemarksWithHotness(
129 "pass-remarks-with-hotness",
130 cl::desc("With PGO, include profile count in optimization remarks"),
133 cl::opt
<std::optional
<uint64_t>, false, remarks::HotnessThresholdParser
>
134 RemarksHotnessThreshold(
135 "pass-remarks-hotness-threshold",
136 cl::desc("Minimum profile count required for an "
137 "optimization remark to be output."
138 " Use 'auto' to apply the threshold from profile summary."),
139 cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden
);
141 static cl::opt
<std::string
>
142 RemarksFilename("pass-remarks-output",
143 cl::desc("Output filename for pass remarks"),
144 cl::value_desc("filename"));
146 static cl::opt
<std::string
>
147 RemarksPasses("pass-remarks-filter",
148 cl::desc("Only record optimization remarks from passes whose "
149 "names match the given regular expression"),
150 cl::value_desc("regex"));
152 static cl::opt
<std::string
> RemarksFormat(
153 "pass-remarks-format",
154 cl::desc("The format used for serializing remarks (default: YAML)"),
155 cl::value_desc("format"), cl::init("yaml"));
157 static cl::opt
<std::string
>
158 SamplePGOFile("lto-sample-profile-file",
159 cl::desc("Specify a SamplePGO profile file"));
161 static cl::opt
<std::string
>
162 CSPGOFile("lto-cspgo-profile-file",
163 cl::desc("Specify a context sensitive PGO profile file"));
166 RunCSIRInstr("lto-cspgo-gen",
167 cl::desc("Run PGO context sensitive IR instrumentation"),
171 DebugPassManager("debug-pass-manager", cl::Hidden
,
172 cl::desc("Print pass management debugging information"));
174 static cl::opt
<std::string
>
175 StatsFile("stats-file", cl::desc("Filename to write statistics to"));
177 static cl::list
<std::string
>
178 PassPlugins("load-pass-plugin",
179 cl::desc("Load passes from plugin library"));
181 static cl::opt
<std::string
> UnifiedLTOMode("unified-lto", cl::Optional
,
182 cl::desc("Set LTO mode"),
183 cl::value_desc("mode"));
185 static cl::opt
<bool> EnableFreestanding(
187 cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
190 static cl::opt
<bool> TryUseNewDbgInfoFormat(
191 "try-experimental-debuginfo-iterators",
192 cl::desc("Enable debuginfo iterator positions, if they're built in"),
193 cl::init(false), cl::Hidden
);
195 extern cl::opt
<bool> UseNewDbgInfoFormat
;
196 extern cl::opt
<cl::boolOrDefault
> LoadBitcodeIntoNewDbgInfoFormat
;
197 extern cl::opt
<cl::boolOrDefault
> PreserveInputDbgFormat
;
199 static void check(Error E
, std::string Msg
) {
202 handleAllErrors(std::move(E
), [&](ErrorInfoBase
&EIB
) {
203 errs() << "llvm-lto2: " << Msg
<< ": " << EIB
.message().c_str() << '\n';
208 template <typename T
> static T
check(Expected
<T
> E
, std::string Msg
) {
210 return std::move(*E
);
211 check(E
.takeError(), Msg
);
215 static void check(std::error_code EC
, std::string Msg
) {
216 check(errorCodeToError(EC
), Msg
);
219 template <typename T
> static T
check(ErrorOr
<T
> E
, std::string Msg
) {
221 return std::move(*E
);
222 check(E
.getError(), Msg
);
227 errs() << "Available subcommands: dump-symtab run\n";
231 static int run(int argc
, char **argv
) {
232 cl::ParseCommandLineOptions(argc
, argv
, "Resolution-based LTO test harness");
233 // Load bitcode into the new debug info format by default.
234 if (LoadBitcodeIntoNewDbgInfoFormat
== cl::boolOrDefault::BOU_UNSET
)
235 LoadBitcodeIntoNewDbgInfoFormat
= cl::boolOrDefault::BOU_TRUE
;
237 // RemoveDIs debug-info transition: tests may request that we /try/ to use the
238 // new debug-info format.
239 if (TryUseNewDbgInfoFormat
) {
240 // Turn the new debug-info format on.
241 UseNewDbgInfoFormat
= true;
243 // Since llvm-lto2 collects multiple IR modules together, for simplicity's
244 // sake we disable the "PreserveInputDbgFormat" flag to enforce a single debug
246 PreserveInputDbgFormat
= cl::boolOrDefault::BOU_FALSE
;
248 // FIXME: Workaround PR30396 which means that a symbol can appear
249 // more than once if it is defined in module-level assembly and
250 // has a GV declaration. We allow (file, symbol) pairs to have multiple
251 // resolutions and apply them in the order observed.
252 std::map
<std::pair
<std::string
, std::string
>, std::list
<SymbolResolution
>>
253 CommandLineResolutions
;
254 for (StringRef R
: SymbolResolutions
) {
255 StringRef Rest
, FileName
, SymbolName
;
256 std::tie(FileName
, Rest
) = R
.split(',');
258 llvm::errs() << "invalid resolution: " << R
<< '\n';
261 std::tie(SymbolName
, Rest
) = Rest
.split(',');
262 SymbolResolution Res
;
263 for (char C
: Rest
) {
265 Res
.Prevailing
= true;
267 Res
.FinalDefinitionInLinkageUnit
= true;
269 Res
.VisibleToRegularObj
= true;
271 Res
.LinkerRedefined
= true;
273 llvm::errs() << "invalid character " << C
<< " in resolution: " << R
278 CommandLineResolutions
[{std::string(FileName
), std::string(SymbolName
)}]
282 std::vector
<std::unique_ptr
<MemoryBuffer
>> MBs
;
286 Conf
.CPU
= codegen::getMCPU();
287 Conf
.Options
= codegen::InitTargetOptionsFromCodeGenFlags(Triple());
288 Conf
.MAttrs
= codegen::getMAttrs();
289 if (auto RM
= codegen::getExplicitRelocModel())
290 Conf
.RelocModel
= *RM
;
291 Conf
.CodeModel
= codegen::getExplicitCodeModel();
293 Conf
.DebugPassManager
= DebugPassManager
;
295 if (SaveTemps
&& !SelectSaveTemps
.empty()) {
296 llvm::errs() << "-save-temps cannot be specified with -select-save-temps\n";
299 if (SaveTemps
|| !SelectSaveTemps
.empty()) {
300 DenseSet
<StringRef
> SaveTempsArgs
;
301 for (auto &S
: SelectSaveTemps
)
302 if (is_contained(SaveTempsValues
, S
))
303 SaveTempsArgs
.insert(S
);
305 llvm::errs() << ("invalid -select-save-temps argument: " + S
) << '\n';
308 check(Conf
.addSaveTemps(OutputFilename
+ ".", false, SaveTempsArgs
),
309 "Config::addSaveTemps failed");
312 // Optimization remarks.
313 Conf
.RemarksFilename
= RemarksFilename
;
314 Conf
.RemarksPasses
= RemarksPasses
;
315 Conf
.RemarksWithHotness
= RemarksWithHotness
;
316 Conf
.RemarksHotnessThreshold
= RemarksHotnessThreshold
;
317 Conf
.RemarksFormat
= RemarksFormat
;
319 Conf
.SampleProfile
= SamplePGOFile
;
320 Conf
.CSIRProfile
= CSPGOFile
;
321 Conf
.RunCSIRInstr
= RunCSIRInstr
;
323 // Run a custom pipeline, if asked for.
324 Conf
.OptPipeline
= OptPipeline
;
325 Conf
.AAPipeline
= AAPipeline
;
327 Conf
.OptLevel
= OptLevel
- '0';
328 Conf
.Freestanding
= EnableFreestanding
;
329 for (auto &PluginFN
: PassPlugins
)
330 Conf
.PassPlugins
.push_back(PluginFN
);
331 if (auto Level
= CodeGenOpt::parseLevel(CGOptLevel
)) {
332 Conf
.CGOptLevel
= *Level
;
334 llvm::errs() << "invalid cg optimization level: " << CGOptLevel
<< '\n';
338 if (auto FT
= codegen::getExplicitFileType())
339 Conf
.CGFileType
= *FT
;
341 Conf
.OverrideTriple
= OverrideTriple
;
342 Conf
.DefaultTriple
= DefaultTriple
;
343 Conf
.StatsFile
= StatsFile
;
344 Conf
.PTO
.LoopVectorization
= Conf
.OptLevel
> 1;
345 Conf
.PTO
.SLPVectorization
= Conf
.OptLevel
> 1;
348 if (ThinLTODistributedIndexes
)
349 Backend
= createWriteIndexesThinBackend(llvm::hardware_concurrency(Threads
),
352 /*NativeObjectPrefix=*/"",
354 /*LinkedObjectsFile=*/nullptr,
357 Backend
= createInProcessThinBackend(
358 llvm::heavyweight_hardware_concurrency(Threads
),
359 /* OnWrite */ {}, ThinLTOEmitIndexes
, ThinLTOEmitImports
);
361 // Track whether we hit an error; in particular, in the multi-threaded case,
362 // we can't exit() early because the rest of the threads wouldn't have had a
363 // change to be join-ed, and that would result in a "terminate called without
364 // an active exception". Altogether, this results in nondeterministic
365 // behavior. Instead, we don't exit in the multi-threaded case, but we make
366 // sure to report the error and then at the end (after joining cleanly)
368 std::atomic
<bool> HasErrors
;
369 std::atomic_init(&HasErrors
, false);
370 Conf
.DiagHandler
= [&](const DiagnosticInfo
&DI
) {
371 DiagnosticPrinterRawOStream
DP(errs());
374 if (DI
.getSeverity() == DS_Error
)
378 LTO::LTOKind LTOMode
= LTO::LTOK_Default
;
380 if (UnifiedLTOMode
== "full") {
381 LTOMode
= LTO::LTOK_UnifiedRegular
;
382 } else if (UnifiedLTOMode
== "thin") {
383 LTOMode
= LTO::LTOK_UnifiedThin
;
384 } else if (UnifiedLTOMode
== "default") {
385 LTOMode
= LTO::LTOK_Default
;
386 } else if (!UnifiedLTOMode
.empty()) {
387 llvm::errs() << "invalid LTO mode\n";
391 LTO
Lto(std::move(Conf
), std::move(Backend
), 1, LTOMode
);
393 for (std::string F
: InputFilenames
) {
394 std::unique_ptr
<MemoryBuffer
> MB
= check(MemoryBuffer::getFile(F
), F
);
395 std::unique_ptr
<InputFile
> Input
=
396 check(InputFile::create(MB
->getMemBufferRef()), F
);
398 std::vector
<SymbolResolution
> Res
;
399 for (const InputFile::Symbol
&Sym
: Input
->symbols()) {
400 auto I
= CommandLineResolutions
.find({F
, std::string(Sym
.getName())});
401 // If it isn't found, look for ".", which would have been added
402 // (followed by a hash) when the symbol was promoted during module
403 // splitting if it was defined in one part and used in the other.
404 // Try looking up the symbol name before the suffix.
405 if (I
== CommandLineResolutions
.end()) {
406 auto SplitName
= Sym
.getName().rsplit(".");
407 I
= CommandLineResolutions
.find({F
, std::string(SplitName
.first
)});
409 if (I
== CommandLineResolutions
.end()) {
410 llvm::errs() << argv
[0] << ": missing symbol resolution for " << F
411 << ',' << Sym
.getName() << '\n';
414 Res
.push_back(I
->second
.front());
415 I
->second
.pop_front();
416 if (I
->second
.empty())
417 CommandLineResolutions
.erase(I
);
424 MBs
.push_back(std::move(MB
));
425 check(Lto
.add(std::move(Input
), Res
), F
);
428 if (!CommandLineResolutions
.empty()) {
430 for (auto UnusedRes
: CommandLineResolutions
)
431 llvm::errs() << argv
[0] << ": unused symbol resolution for "
432 << UnusedRes
.first
.first
<< ',' << UnusedRes
.first
.second
440 const Twine
&ModuleName
) -> std::unique_ptr
<CachedFileStream
> {
441 std::string Path
= OutputFilename
+ "." + utostr(Task
);
444 auto S
= std::make_unique
<raw_fd_ostream
>(Path
, EC
, sys::fs::OF_None
);
446 return std::make_unique
<CachedFileStream
>(std::move(S
), Path
);
449 auto AddBuffer
= [&](size_t Task
, const Twine
&ModuleName
,
450 std::unique_ptr
<MemoryBuffer
> MB
) {
451 *AddStream(Task
, ModuleName
)->OS
<< MB
->getBuffer();
455 if (!CacheDir
.empty())
456 Cache
= check(localCache("ThinLTO", "Thin", CacheDir
, AddBuffer
),
457 "failed to create cache");
459 check(Lto
.run(AddStream
, Cache
), "LTO::run failed");
460 return static_cast<int>(HasErrors
);
463 static int dumpSymtab(int argc
, char **argv
) {
464 for (StringRef F
: make_range(argv
+ 1, argv
+ argc
)) {
465 std::unique_ptr
<MemoryBuffer
> MB
=
466 check(MemoryBuffer::getFile(F
), std::string(F
));
467 BitcodeFileContents BFC
=
468 check(getBitcodeFileContents(*MB
), std::string(F
));
470 if (BFC
.Symtab
.size() >= sizeof(irsymtab::storage::Header
)) {
471 auto *Hdr
= reinterpret_cast<const irsymtab::storage::Header
*>(
473 outs() << "version: " << Hdr
->Version
<< '\n';
474 if (Hdr
->Version
== irsymtab::storage::Header::kCurrentVersion
)
475 outs() << "producer: " << Hdr
->Producer
.get(BFC
.StrtabForSymtab
)
479 std::unique_ptr
<InputFile
> Input
=
480 check(InputFile::create(MB
->getMemBufferRef()), std::string(F
));
482 outs() << "target triple: " << Input
->getTargetTriple() << '\n';
483 Triple
TT(Input
->getTargetTriple());
485 outs() << "source filename: " << Input
->getSourceFileName() << '\n';
487 if (TT
.isOSBinFormatCOFF())
488 outs() << "linker opts: " << Input
->getCOFFLinkerOpts() << '\n';
490 if (TT
.isOSBinFormatELF()) {
491 outs() << "dependent libraries:";
492 for (auto L
: Input
->getDependentLibraries())
493 outs() << " \"" << L
<< "\"";
497 ArrayRef
<std::pair
<StringRef
, Comdat::SelectionKind
>> ComdatTable
=
498 Input
->getComdatTable();
499 for (const InputFile::Symbol
&Sym
: Input
->symbols()) {
500 switch (Sym
.getVisibility()) {
501 case GlobalValue::HiddenVisibility
:
504 case GlobalValue::ProtectedVisibility
:
507 case GlobalValue::DefaultVisibility
:
512 auto PrintBool
= [&](char C
, bool B
) { outs() << (B
? C
: '-'); };
513 PrintBool('U', Sym
.isUndefined());
514 PrintBool('C', Sym
.isCommon());
515 PrintBool('W', Sym
.isWeak());
516 PrintBool('I', Sym
.isIndirect());
517 PrintBool('O', Sym
.canBeOmittedFromSymbolTable());
518 PrintBool('T', Sym
.isTLS());
519 PrintBool('X', Sym
.isExecutable());
520 outs() << ' ' << Sym
.getName() << '\n';
523 outs() << " size " << Sym
.getCommonSize() << " align "
524 << Sym
.getCommonAlignment() << '\n';
526 int Comdat
= Sym
.getComdatIndex();
528 outs() << " comdat ";
529 switch (ComdatTable
[Comdat
].second
) {
533 case Comdat::ExactMatch
:
534 outs() << "exactmatch";
536 case Comdat::Largest
:
539 case Comdat::NoDeduplicate
:
540 outs() << "nodeduplicate";
542 case Comdat::SameSize
:
543 outs() << "samesize";
546 outs() << ' ' << ComdatTable
[Comdat
].first
<< '\n';
549 if (TT
.isOSBinFormatCOFF() && Sym
.isWeak() && Sym
.isIndirect())
550 outs() << " fallback " << Sym
.getCOFFWeakExternalFallback() << '\n';
552 if (!Sym
.getSectionName().empty())
553 outs() << " section " << Sym
.getSectionName() << "\n";
562 int main(int argc
, char **argv
) {
563 InitLLVM
X(argc
, argv
);
564 InitializeAllTargets();
565 InitializeAllTargetMCs();
566 InitializeAllAsmPrinters();
567 InitializeAllAsmParsers();
569 // FIXME: This should use llvm::cl subcommands, but it isn't currently
570 // possible to pass an argument not associated with a subcommand to a
571 // subcommand (e.g. -use-new-pm).
575 StringRef Subcommand
= argv
[1];
576 // Ensure that argv[0] is correct after adjusting argv/argc.
578 if (Subcommand
== "dump-symtab")
579 return dumpSymtab(argc
- 1, argv
+ 1);
580 if (Subcommand
== "run")
581 return run(argc
- 1, argv
+ 1);