1//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===//
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 file implements the Link Time Optimization library. This library is
10// intended to be used by linker to optimize code at link time.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/LTO/legacy/LTOCodeGenerator.h"
15
16#include "llvm/ADT/Statistic.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Analysis/TargetLibraryInfo.h"
19#include "llvm/Analysis/TargetTransformInfo.h"
20#include "llvm/Bitcode/BitcodeWriter.h"
21#include "llvm/CodeGen/CommandFlags.h"
22#include "llvm/CodeGen/TargetSubtargetInfo.h"
23#include "llvm/Config/config.h"
24#include "llvm/IR/DataLayout.h"
25#include "llvm/IR/DebugInfo.h"
26#include "llvm/IR/DerivedTypes.h"
27#include "llvm/IR/DiagnosticInfo.h"
28#include "llvm/IR/DiagnosticPrinter.h"
29#include "llvm/IR/LLVMContext.h"
30#include "llvm/IR/LLVMRemarkStreamer.h"
31#include "llvm/IR/LegacyPassManager.h"
32#include "llvm/IR/Mangler.h"
33#include "llvm/IR/Module.h"
34#include "llvm/IR/PassTimingInfo.h"
35#include "llvm/IR/Verifier.h"
36#include "llvm/LTO/LTO.h"
37#include "llvm/LTO/LTOBackend.h"
38#include "llvm/LTO/legacy/LTOModule.h"
39#include "llvm/LTO/legacy/UpdateCompilerUsed.h"
40#include "llvm/Linker/Linker.h"
41#include "llvm/MC/TargetRegistry.h"
42#include "llvm/Remarks/HotnessThresholdParser.h"
43#include "llvm/Support/CommandLine.h"
44#include "llvm/Support/FileSystem.h"
45#include "llvm/Support/MemoryBuffer.h"
46#include "llvm/Support/Process.h"
47#include "llvm/Support/Signals.h"
48#include "llvm/Support/ToolOutputFile.h"
49#include "llvm/Support/raw_ostream.h"
50#include "llvm/Target/TargetOptions.h"
51#include "llvm/TargetParser/Host.h"
52#include "llvm/TargetParser/SubtargetFeature.h"
53#include "llvm/Transforms/IPO.h"
54#include "llvm/Transforms/IPO/Internalize.h"
55#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
56#include "llvm/Transforms/Utils/ModuleUtils.h"
57#include <optional>
58#include <system_error>
59using namespace llvm;
60
61const char* LTOCodeGenerator::getVersionString() {
62 return PACKAGE_NAME " version " PACKAGE_VERSION;
63}
64
65namespace llvm {
66cl::opt<bool> LTODiscardValueNames(
67 "lto-discard-value-names",
68 cl::desc("Strip names from Value during LTO (other than GlobalValue)."),
69#ifdef NDEBUG
70 cl::init(Val: true),
71#else
72 cl::init(false),
73#endif
74 cl::Hidden);
75
76cl::opt<bool> RemarksWithHotness(
77 "lto-pass-remarks-with-hotness",
78 cl::desc("With PGO, include profile count in optimization remarks"),
79 cl::Hidden);
80
81cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
82 RemarksHotnessThreshold(
83 "lto-pass-remarks-hotness-threshold",
84 cl::desc("Minimum profile count required for an "
85 "optimization remark to be output."
86 " Use 'auto' to apply the threshold from profile summary."),
87 cl::value_desc("uint or 'auto'"), cl::init(Val: 0), cl::Hidden);
88
89cl::opt<std::string>
90 RemarksFilename("lto-pass-remarks-output",
91 cl::desc("Output filename for pass remarks"),
92 cl::value_desc("filename"));
93
94cl::opt<std::string>
95 RemarksPasses("lto-pass-remarks-filter",
96 cl::desc("Only record optimization remarks from passes whose "
97 "names match the given regular expression"),
98 cl::value_desc("regex"));
99
100cl::opt<std::string> RemarksFormat(
101 "lto-pass-remarks-format",
102 cl::desc("The format used for serializing remarks (default: YAML)"),
103 cl::value_desc("format"), cl::init(Val: "yaml"));
104
105static cl::opt<std::string>
106 LTOStatsFile("lto-stats-file",
107 cl::desc("Save statistics to the specified file"), cl::Hidden);
108
109static cl::opt<std::string> AIXSystemAssemblerPath(
110 "lto-aix-system-assembler",
111 cl::desc("Path to a system assembler, picked up on AIX only"),
112 cl::value_desc("path"));
113
114static cl::opt<bool>
115 LTORunCSIRInstr("cs-profile-generate",
116 cl::desc("Perform context sensitive PGO instrumentation"));
117
118static cl::opt<std::string>
119 LTOCSIRProfile("cs-profile-path",
120 cl::desc("Context sensitive profile file path"));
121} // namespace llvm
122
123LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context)
124 : Context(Context), MergedModule(new Module("ld-temp.o", Context)),
125 TheLinker(new Linker(*MergedModule)) {
126 Context.setDiscardValueNames(LTODiscardValueNames);
127 Context.enableDebugTypeODRUniquing();
128
129 Config.CodeModel = std::nullopt;
130 Config.StatsFile = LTOStatsFile;
131 Config.RunCSIRInstr = LTORunCSIRInstr;
132 Config.CSIRProfile = LTOCSIRProfile;
133}
134
135LTOCodeGenerator::~LTOCodeGenerator() = default;
136
137void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) {
138 AsmUndefinedRefs.insert_range(R: Mod->getAsmUndefinedRefs());
139}
140
141bool LTOCodeGenerator::addModule(LTOModule *Mod) {
142 assert(&Mod->getModule().getContext() == &Context &&
143 "Expected module in same context");
144
145 bool ret = TheLinker->linkInModule(Src: Mod->takeModule());
146 setAsmUndefinedRefs(Mod);
147
148 // We've just changed the input, so let's make sure we verify it.
149 HasVerifiedInput = false;
150
151 return !ret;
152}
153
154void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) {
155 assert(&Mod->getModule().getContext() == &Context &&
156 "Expected module in same context");
157
158 AsmUndefinedRefs.clear();
159
160 MergedModule = Mod->takeModule();
161 TheLinker = std::make_unique<Linker>(args&: *MergedModule);
162 setAsmUndefinedRefs(&*Mod);
163
164 // We've just changed the input, so let's make sure we verify it.
165 HasVerifiedInput = false;
166}
167
168void LTOCodeGenerator::setTargetOptions(const TargetOptions &Options) {
169 Config.Options = Options;
170}
171
172void LTOCodeGenerator::setDebugInfo(lto_debug_model Debug) {
173 switch (Debug) {
174 case LTO_DEBUG_MODEL_NONE:
175 EmitDwarfDebugInfo = false;
176 return;
177
178 case LTO_DEBUG_MODEL_DWARF:
179 EmitDwarfDebugInfo = true;
180 return;
181 }
182 llvm_unreachable("Unknown debug format!");
183}
184
185void LTOCodeGenerator::setOptLevel(unsigned Level) {
186 Config.OptLevel = Level;
187 Config.PTO.LoopVectorization = Config.OptLevel > 1;
188 Config.PTO.SLPVectorization = Config.OptLevel > 1;
189 std::optional<CodeGenOptLevel> CGOptLevelOrNone =
190 CodeGenOpt::getLevel(OL: Config.OptLevel);
191 assert(CGOptLevelOrNone && "Unknown optimization level!");
192 Config.CGOptLevel = *CGOptLevelOrNone;
193}
194
195bool LTOCodeGenerator::writeMergedModules(StringRef Path) {
196 if (!determineTarget())
197 return false;
198
199 // We always run the verifier once on the merged module.
200 verifyMergedModuleOnce();
201
202 // mark which symbols can not be internalized
203 applyScopeRestrictions();
204
205 // create output file
206 std::error_code EC;
207 ToolOutputFile Out(Path, EC, sys::fs::OF_None);
208 if (EC) {
209 std::string ErrMsg = "could not open bitcode file for writing: ";
210 ErrMsg += Path.str() + ": " + EC.message();
211 emitError(ErrMsg);
212 return false;
213 }
214
215 // write bitcode to it
216 WriteBitcodeToFile(M: *MergedModule, Out&: Out.os(), ShouldPreserveUseListOrder: ShouldEmbedUselists);
217 Out.os().close();
218
219 if (Out.os().has_error()) {
220 std::string ErrMsg = "could not write bitcode file: ";
221 ErrMsg += Path.str() + ": " + Out.os().error().message();
222 emitError(ErrMsg);
223 Out.os().clear_error();
224 return false;
225 }
226
227 Out.keep();
228 return true;
229}
230
231bool LTOCodeGenerator::useAIXSystemAssembler() {
232 const auto &Triple = TargetMach->getTargetTriple();
233 return Triple.isOSAIX() && Config.Options.DisableIntegratedAS;
234}
235
236bool LTOCodeGenerator::runAIXSystemAssembler(SmallString<128> &AssemblyFile) {
237 assert(useAIXSystemAssembler() &&
238 "Runing AIX system assembler when integrated assembler is available!");
239
240 // Set the system assembler path.
241 SmallString<256> AssemblerPath("/usr/bin/as");
242 if (!llvm::AIXSystemAssemblerPath.empty()) {
243 if (llvm::sys::fs::real_path(path: llvm::AIXSystemAssemblerPath, output&: AssemblerPath,
244 /* expand_tilde */ true)) {
245 emitError(
246 ErrMsg: "Cannot find the assembler specified by lto-aix-system-assembler");
247 return false;
248 }
249 }
250
251 // Setup the LDR_CNTRL variable
252 std::string LDR_CNTRL_var = "LDR_CNTRL=MAXDATA32=0xA0000000@DSA";
253 if (std::optional<std::string> V = sys::Process::GetEnv(name: "LDR_CNTRL"))
254 LDR_CNTRL_var += ("@" + *V);
255
256 // Prepare inputs for the assember.
257 const auto &Triple = TargetMach->getTargetTriple();
258 const char *Arch = Triple.isArch64Bit() ? "-a64" : "-a32";
259 std::string ObjectFileName(AssemblyFile);
260 ObjectFileName[ObjectFileName.size() - 1] = 'o';
261 SmallVector<StringRef, 8> Args = {
262 "/bin/env", LDR_CNTRL_var,
263 AssemblerPath, Arch,
264 "-many", "-o",
265 ObjectFileName, AssemblyFile};
266
267 // Invoke the assembler.
268 int RC = sys::ExecuteAndWait(Program: Args[0], Args);
269
270 // Handle errors.
271 if (RC < -1) {
272 emitError(ErrMsg: "LTO assembler exited abnormally");
273 return false;
274 }
275 if (RC < 0) {
276 emitError(ErrMsg: "Unable to invoke LTO assembler");
277 return false;
278 }
279 if (RC > 0) {
280 emitError(ErrMsg: "LTO assembler invocation returned non-zero");
281 return false;
282 }
283
284 // Cleanup.
285 remove(filename: AssemblyFile.c_str());
286
287 // Fix the output file name.
288 AssemblyFile = ObjectFileName;
289
290 return true;
291}
292
293bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) {
294 if (useAIXSystemAssembler())
295 setFileType(CodeGenFileType::AssemblyFile);
296
297 // make unique temp output file to put generated code
298 SmallString<128> Filename;
299
300 auto AddStream =
301 [&](size_t Task,
302 const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
303 StringRef Extension(
304 Config.CGFileType == CodeGenFileType::AssemblyFile ? "s" : "o");
305
306 int FD;
307 std::error_code EC =
308 sys::fs::createTemporaryFile(Prefix: "lto-llvm", Suffix: Extension, ResultFD&: FD, ResultPath&: Filename);
309 if (EC)
310 emitError(ErrMsg: EC.message());
311
312 return std::make_unique<CachedFileStream>(
313 args: std::make_unique<llvm::raw_fd_ostream>(args&: FD, args: true));
314 };
315
316 bool genResult = compileOptimized(AddStream, ParallelismLevel: 1);
317
318 if (!genResult) {
319 sys::fs::remove(path: Twine(Filename));
320 return false;
321 }
322
323 // If statistics were requested, save them to the specified file or
324 // print them out after codegen.
325 if (StatsFile)
326 PrintStatisticsJSON(OS&: StatsFile->os());
327 else if (AreStatisticsEnabled())
328 PrintStatistics();
329
330 if (useAIXSystemAssembler())
331 if (!runAIXSystemAssembler(AssemblyFile&: Filename))
332 return false;
333
334 NativeObjectPath = Filename.c_str();
335 *Name = NativeObjectPath.c_str();
336 return true;
337}
338
339std::unique_ptr<MemoryBuffer>
340LTOCodeGenerator::compileOptimized() {
341 const char *name;
342 if (!compileOptimizedToFile(Name: &name))
343 return nullptr;
344
345 // read .o file into memory buffer
346 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile(
347 Filename: name, /*IsText=*/false, /*RequiresNullTerminator=*/false);
348 if (std::error_code EC = BufferOrErr.getError()) {
349 emitError(ErrMsg: EC.message());
350 sys::fs::remove(path: NativeObjectPath);
351 return nullptr;
352 }
353
354 // remove temp files
355 sys::fs::remove(path: NativeObjectPath);
356
357 return std::move(*BufferOrErr);
358}
359
360bool LTOCodeGenerator::compile_to_file(const char **Name) {
361 if (!optimize())
362 return false;
363
364 return compileOptimizedToFile(Name);
365}
366
367std::unique_ptr<MemoryBuffer> LTOCodeGenerator::compile() {
368 if (!optimize())
369 return nullptr;
370
371 return compileOptimized();
372}
373
374bool LTOCodeGenerator::determineTarget() {
375 if (TargetMach)
376 return true;
377
378 if (MergedModule->getTargetTriple().empty())
379 MergedModule->setTargetTriple(Triple(sys::getDefaultTargetTriple()));
380
381 // create target machine from info for merged modules
382 std::string ErrMsg;
383 MArch = TargetRegistry::lookupTarget(TheTriple: MergedModule->getTargetTriple(), Error&: ErrMsg);
384 if (!MArch) {
385 emitError(ErrMsg);
386 return false;
387 }
388
389 // Construct LTOModule, hand over ownership of module and target. Use MAttr as
390 // the default set of features.
391 SubtargetFeatures Features(join(R&: Config.MAttrs, Separator: ""));
392 Features.getDefaultSubtargetFeatures(Triple: MergedModule->getTargetTriple());
393 FeatureStr = Features.getString();
394 if (Config.CPU.empty())
395 Config.CPU = lto::getThinLTODefaultCPU(TheTriple: MergedModule->getTargetTriple());
396
397 // If data-sections is not explicitly set or unset, set data-sections by
398 // default to match the behaviour of lld and gold plugin.
399 if (!codegen::getExplicitDataSections())
400 Config.Options.DataSections = true;
401
402 TargetMach = createTargetMachine();
403 assert(TargetMach && "Unable to create target machine");
404
405 return true;
406}
407
408std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() {
409 assert(MArch && "MArch is not set!");
410 return std::unique_ptr<TargetMachine>(MArch->createTargetMachine(
411 TT: MergedModule->getTargetTriple(), CPU: Config.CPU, Features: FeatureStr, Options: Config.Options,
412 RM: Config.RelocModel, CM: std::nullopt, OL: Config.CGOptLevel));
413}
414
415// If a linkonce global is present in the MustPreserveSymbols, we need to make
416// sure we honor this. To force the compiler to not drop it, we add it to the
417// "llvm.compiler.used" global.
418void LTOCodeGenerator::preserveDiscardableGVs(
419 Module &TheModule,
420 llvm::function_ref<bool(const GlobalValue &)> mustPreserveGV) {
421 std::vector<GlobalValue *> Used;
422 auto mayPreserveGlobal = [&](GlobalValue &GV) {
423 if (!GV.isDiscardableIfUnused() || GV.isDeclaration() ||
424 !mustPreserveGV(GV))
425 return;
426 if (GV.hasAvailableExternallyLinkage())
427 return emitWarning(
428 ErrMsg: (Twine("Linker asked to preserve available_externally global: '") +
429 GV.getName() + "'").str());
430 if (GV.hasInternalLinkage())
431 return emitWarning(ErrMsg: (Twine("Linker asked to preserve internal global: '") +
432 GV.getName() + "'").str());
433 Used.push_back(x: &GV);
434 };
435 for (auto &GV : TheModule)
436 mayPreserveGlobal(GV);
437 for (auto &GV : TheModule.globals())
438 mayPreserveGlobal(GV);
439 for (auto &GV : TheModule.aliases())
440 mayPreserveGlobal(GV);
441
442 if (Used.empty())
443 return;
444
445 appendToCompilerUsed(M&: TheModule, Values: Used);
446}
447
448void LTOCodeGenerator::applyScopeRestrictions() {
449 if (ScopeRestrictionsDone)
450 return;
451
452 // Declare a callback for the internalize pass that will ask for every
453 // candidate GlobalValue if it can be internalized or not.
454 Mangler Mang;
455 SmallString<64> MangledName;
456 auto mustPreserveGV = [&](const GlobalValue &GV) -> bool {
457 // Unnamed globals can't be mangled, but they can't be preserved either.
458 if (!GV.hasName())
459 return false;
460
461 // Need to mangle the GV as the "MustPreserveSymbols" StringSet is filled
462 // with the linker supplied name, which on Darwin includes a leading
463 // underscore.
464 MangledName.clear();
465 MangledName.reserve(N: GV.getName().size() + 1);
466 Mang.getNameWithPrefix(OutName&: MangledName, GV: &GV, /*CannotUsePrivateLabel=*/false);
467 return MustPreserveSymbols.count(Key: MangledName);
468 };
469
470 // Preserve linkonce value on linker request
471 preserveDiscardableGVs(TheModule&: *MergedModule, mustPreserveGV);
472
473 if (!ShouldInternalize)
474 return;
475
476 if (ShouldRestoreGlobalsLinkage) {
477 // Record the linkage type of non-local symbols so they can be restored
478 // prior
479 // to module splitting.
480 auto RecordLinkage = [&](const GlobalValue &GV) {
481 if (!GV.hasAvailableExternallyLinkage() && !GV.hasLocalLinkage() &&
482 GV.hasName())
483 ExternalSymbols.insert(KV: std::make_pair(x: GV.getName(), y: GV.getLinkage()));
484 };
485 for (auto &GV : *MergedModule)
486 RecordLinkage(GV);
487 for (auto &GV : MergedModule->globals())
488 RecordLinkage(GV);
489 for (auto &GV : MergedModule->aliases())
490 RecordLinkage(GV);
491 }
492
493 // Update the llvm.compiler_used globals to force preserving libcalls and
494 // symbols referenced from asm
495 updateCompilerUsed(TheModule&: *MergedModule, TM: *TargetMach, AsmUndefinedRefs);
496
497 internalizeModule(TheModule&: *MergedModule, MustPreserveGV: mustPreserveGV);
498
499 ScopeRestrictionsDone = true;
500}
501
502/// Restore original linkage for symbols that may have been internalized
503void LTOCodeGenerator::restoreLinkageForExternals() {
504 if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage)
505 return;
506
507 assert(ScopeRestrictionsDone &&
508 "Cannot externalize without internalization!");
509
510 if (ExternalSymbols.empty())
511 return;
512
513 auto externalize = [this](GlobalValue &GV) {
514 if (!GV.hasLocalLinkage() || !GV.hasName())
515 return;
516
517 auto I = ExternalSymbols.find(Key: GV.getName());
518 if (I == ExternalSymbols.end())
519 return;
520
521 GV.setLinkage(I->second);
522 };
523
524 llvm::for_each(Range: MergedModule->functions(), F: externalize);
525 llvm::for_each(Range: MergedModule->globals(), F: externalize);
526 llvm::for_each(Range: MergedModule->aliases(), F: externalize);
527}
528
529void LTOCodeGenerator::verifyMergedModuleOnce() {
530 // Only run on the first call.
531 if (HasVerifiedInput)
532 return;
533 HasVerifiedInput = true;
534
535 bool BrokenDebugInfo = false;
536 if (verifyModule(M: *MergedModule, OS: &dbgs(), BrokenDebugInfo: &BrokenDebugInfo))
537 report_fatal_error(reason: "Broken module found, compilation aborted!");
538 if (BrokenDebugInfo) {
539 emitWarning(ErrMsg: "Invalid debug info found, debug info will be stripped");
540 StripDebugInfo(M&: *MergedModule);
541 }
542}
543
544void LTOCodeGenerator::finishOptimizationRemarks() {
545 if (DiagnosticOutputFile) {
546 DiagnosticOutputFile->keep();
547 // FIXME: LTOCodeGenerator dtor is not invoked on Darwin
548 DiagnosticOutputFile.finalize();
549 DiagnosticOutputFile->os().flush();
550 }
551}
552
553/// Optimize merged modules using various IPO passes
554bool LTOCodeGenerator::optimize() {
555 if (!this->determineTarget())
556 return false;
557
558 // libLTO parses options late, so re-set them here.
559 Context.setDiscardValueNames(LTODiscardValueNames);
560
561 auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
562 Context, RemarksFilename, RemarksPasses, RemarksFormat,
563 RemarksWithHotness, RemarksHotnessThreshold);
564 if (!DiagFileOrErr) {
565 errs() << "Error: " << toString(E: DiagFileOrErr.takeError()) << "\n";
566 report_fatal_error(reason: "Can't get an output file for the remarks");
567 }
568 DiagnosticOutputFile = std::move(*DiagFileOrErr);
569
570 // Setup output file to emit statistics.
571 auto StatsFileOrErr = lto::setupStatsFile(LTOStatsFile);
572 if (!StatsFileOrErr) {
573 errs() << "Error: " << toString(E: StatsFileOrErr.takeError()) << "\n";
574 report_fatal_error(reason: "Can't get an output file for the statistics");
575 }
576 StatsFile = std::move(StatsFileOrErr.get());
577
578 // Currently there is no support for enabling whole program visibility via a
579 // linker option in the old LTO API, but this call allows it to be specified
580 // via the internal option. Must be done before WPD invoked via the optimizer
581 // pipeline run below.
582 updatePublicTypeTestCalls(M&: *MergedModule,
583 /* WholeProgramVisibilityEnabledInLTO */ false);
584 updateVCallVisibilityInModule(
585 M&: *MergedModule,
586 /* WholeProgramVisibilityEnabledInLTO */ false,
587 // FIXME: These need linker information via a
588 // TBD new interface.
589 /*DynamicExportSymbols=*/{},
590 /*ValidateAllVtablesHaveTypeInfos=*/false,
591 /*IsVisibleToRegularObj=*/[](StringRef) { return true; });
592
593 // We always run the verifier once on the merged module, the `DisableVerify`
594 // parameter only applies to subsequent verify.
595 verifyMergedModuleOnce();
596
597 // Mark which symbols can not be internalized
598 this->applyScopeRestrictions();
599
600 // Add an appropriate DataLayout instance for this module...
601 MergedModule->setDataLayout(TargetMach->createDataLayout());
602
603 if (!SaveIRBeforeOptPath.empty()) {
604 std::error_code EC;
605 raw_fd_ostream OS(SaveIRBeforeOptPath, EC, sys::fs::OF_None);
606 if (EC)
607 report_fatal_error(reason: Twine("Failed to open ") + SaveIRBeforeOptPath +
608 " to save optimized bitcode\n");
609 WriteBitcodeToFile(M: *MergedModule, Out&: OS,
610 /* ShouldPreserveUseListOrder */ true);
611 }
612
613 ModuleSummaryIndex CombinedIndex(false);
614 TargetMach = createTargetMachine();
615 if (!opt(Conf: Config, TM: TargetMach.get(), Task: 0, Mod&: *MergedModule, /*IsThinLTO=*/false,
616 /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
617 /*CmdArgs*/ std::vector<uint8_t>())) {
618 emitError(ErrMsg: "LTO middle-end optimizations failed");
619 return false;
620 }
621
622 return true;
623}
624
625bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream,
626 unsigned ParallelismLevel) {
627 if (!this->determineTarget())
628 return false;
629
630 // We always run the verifier once on the merged module. If it has already
631 // been called in optimize(), this call will return early.
632 verifyMergedModuleOnce();
633
634 // Re-externalize globals that may have been internalized to increase scope
635 // for splitting
636 restoreLinkageForExternals();
637
638 ModuleSummaryIndex CombinedIndex(false);
639
640 Config.CodeGenOnly = true;
641 Error Err = backend(C: Config, AddStream, ParallelCodeGenParallelismLevel: ParallelismLevel, M&: *MergedModule,
642 CombinedIndex);
643 assert(!Err && "unexpected code-generation failure");
644 (void)Err;
645
646 // If statistics were requested, save them to the specified file or
647 // print them out after codegen.
648 if (StatsFile)
649 PrintStatisticsJSON(OS&: StatsFile->os());
650 else if (AreStatisticsEnabled())
651 PrintStatistics();
652
653 reportAndResetTimings();
654
655 finishOptimizationRemarks();
656
657 return true;
658}
659
660void LTOCodeGenerator::setCodeGenDebugOptions(ArrayRef<StringRef> Options) {
661 for (StringRef Option : Options)
662 CodegenOptions.push_back(x: Option.str());
663}
664
665void LTOCodeGenerator::parseCodeGenDebugOptions() {
666 if (!CodegenOptions.empty())
667 llvm::parseCommandLineOptions(Options&: CodegenOptions);
668}
669
670void llvm::parseCommandLineOptions(std::vector<std::string> &Options) {
671 if (!Options.empty()) {
672 // ParseCommandLineOptions() expects argv[0] to be program name.
673 std::vector<const char *> CodegenArgv(1, "libLLVMLTO");
674 for (std::string &Arg : Options)
675 CodegenArgv.push_back(x: Arg.c_str());
676 cl::ParseCommandLineOptions(argc: CodegenArgv.size(), argv: CodegenArgv.data());
677 }
678}
679
680void LTOCodeGenerator::DiagnosticHandler(const DiagnosticInfo &DI) {
681 // Map the LLVM internal diagnostic severity to the LTO diagnostic severity.
682 lto_codegen_diagnostic_severity_t Severity;
683 switch (DI.getSeverity()) {
684 case DS_Error:
685 Severity = LTO_DS_ERROR;
686 break;
687 case DS_Warning:
688 Severity = LTO_DS_WARNING;
689 break;
690 case DS_Remark:
691 Severity = LTO_DS_REMARK;
692 break;
693 case DS_Note:
694 Severity = LTO_DS_NOTE;
695 break;
696 }
697 // Create the string that will be reported to the external diagnostic handler.
698 std::string MsgStorage;
699 raw_string_ostream Stream(MsgStorage);
700 DiagnosticPrinterRawOStream DP(Stream);
701 DI.print(DP);
702
703 // If this method has been called it means someone has set up an external
704 // diagnostic handler. Assert on that.
705 assert(DiagHandler && "Invalid diagnostic handler");
706 (*DiagHandler)(Severity, MsgStorage.c_str(), DiagContext);
707}
708
709namespace {
710struct LTODiagnosticHandler : public DiagnosticHandler {
711 LTOCodeGenerator *CodeGenerator;
712 LTODiagnosticHandler(LTOCodeGenerator *CodeGenPtr)
713 : CodeGenerator(CodeGenPtr) {}
714 bool handleDiagnostics(const DiagnosticInfo &DI) override {
715 CodeGenerator->DiagnosticHandler(DI);
716 return true;
717 }
718};
719}
720
721void
722LTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_t DiagHandler,
723 void *Ctxt) {
724 this->DiagHandler = DiagHandler;
725 this->DiagContext = Ctxt;
726 if (!DiagHandler)
727 return Context.setDiagnosticHandler(DH: nullptr);
728 // Register the LTOCodeGenerator stub in the LLVMContext to forward the
729 // diagnostic to the external DiagHandler.
730 Context.setDiagnosticHandler(DH: std::make_unique<LTODiagnosticHandler>(args: this),
731 RespectFilters: true);
732}
733
734namespace {
735class LTODiagnosticInfo : public DiagnosticInfo {
736 const Twine &Msg;
737public:
738 LTODiagnosticInfo(const Twine &DiagMsg LLVM_LIFETIME_BOUND,
739 DiagnosticSeverity Severity = DS_Error)
740 : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
741 void print(DiagnosticPrinter &DP) const override { DP << Msg; }
742};
743}
744
745void LTOCodeGenerator::emitError(const std::string &ErrMsg) {
746 if (DiagHandler)
747 (*DiagHandler)(LTO_DS_ERROR, ErrMsg.c_str(), DiagContext);
748 else
749 Context.diagnose(DI: LTODiagnosticInfo(ErrMsg));
750}
751
752void LTOCodeGenerator::emitWarning(const std::string &ErrMsg) {
753 if (DiagHandler)
754 (*DiagHandler)(LTO_DS_WARNING, ErrMsg.c_str(), DiagContext);
755 else
756 Context.diagnose(DI: LTODiagnosticInfo(ErrMsg, DS_Warning));
757}
758