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(true),
71#else
72 cl::init(Val: 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 TripleStr = MergedModule->getTargetTriple().str();
379 llvm::Triple Triple(TripleStr);
380 if (TripleStr.empty()) {
381 TripleStr = sys::getDefaultTargetTriple();
382 MergedModule->setTargetTriple(Triple);
383 }
384
385 // create target machine from info for merged modules
386 std::string ErrMsg;
387 MArch = TargetRegistry::lookupTarget(TripleStr, Error&: ErrMsg);
388 if (!MArch) {
389 emitError(ErrMsg);
390 return false;
391 }
392
393 // Construct LTOModule, hand over ownership of module and target. Use MAttr as
394 // the default set of features.
395 SubtargetFeatures Features(join(R&: Config.MAttrs, Separator: ""));
396 Features.getDefaultSubtargetFeatures(Triple);
397 FeatureStr = Features.getString();
398 if (Config.CPU.empty())
399 Config.CPU = lto::getThinLTODefaultCPU(TheTriple: Triple);
400
401 // If data-sections is not explicitly set or unset, set data-sections by
402 // default to match the behaviour of lld and gold plugin.
403 if (!codegen::getExplicitDataSections())
404 Config.Options.DataSections = true;
405
406 TargetMach = createTargetMachine();
407 assert(TargetMach && "Unable to create target machine");
408
409 return true;
410}
411
412std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() {
413 assert(MArch && "MArch is not set!");
414 return std::unique_ptr<TargetMachine>(MArch->createTargetMachine(
415 TT: Triple(TripleStr), CPU: Config.CPU, Features: FeatureStr, Options: Config.Options,
416 RM: Config.RelocModel, CM: std::nullopt, OL: Config.CGOptLevel));
417}
418
419// If a linkonce global is present in the MustPreserveSymbols, we need to make
420// sure we honor this. To force the compiler to not drop it, we add it to the
421// "llvm.compiler.used" global.
422void LTOCodeGenerator::preserveDiscardableGVs(
423 Module &TheModule,
424 llvm::function_ref<bool(const GlobalValue &)> mustPreserveGV) {
425 std::vector<GlobalValue *> Used;
426 auto mayPreserveGlobal = [&](GlobalValue &GV) {
427 if (!GV.isDiscardableIfUnused() || GV.isDeclaration() ||
428 !mustPreserveGV(GV))
429 return;
430 if (GV.hasAvailableExternallyLinkage())
431 return emitWarning(
432 ErrMsg: (Twine("Linker asked to preserve available_externally global: '") +
433 GV.getName() + "'").str());
434 if (GV.hasInternalLinkage())
435 return emitWarning(ErrMsg: (Twine("Linker asked to preserve internal global: '") +
436 GV.getName() + "'").str());
437 Used.push_back(x: &GV);
438 };
439 for (auto &GV : TheModule)
440 mayPreserveGlobal(GV);
441 for (auto &GV : TheModule.globals())
442 mayPreserveGlobal(GV);
443 for (auto &GV : TheModule.aliases())
444 mayPreserveGlobal(GV);
445
446 if (Used.empty())
447 return;
448
449 appendToCompilerUsed(M&: TheModule, Values: Used);
450}
451
452void LTOCodeGenerator::applyScopeRestrictions() {
453 if (ScopeRestrictionsDone)
454 return;
455
456 // Declare a callback for the internalize pass that will ask for every
457 // candidate GlobalValue if it can be internalized or not.
458 Mangler Mang;
459 SmallString<64> MangledName;
460 auto mustPreserveGV = [&](const GlobalValue &GV) -> bool {
461 // Unnamed globals can't be mangled, but they can't be preserved either.
462 if (!GV.hasName())
463 return false;
464
465 // Need to mangle the GV as the "MustPreserveSymbols" StringSet is filled
466 // with the linker supplied name, which on Darwin includes a leading
467 // underscore.
468 MangledName.clear();
469 MangledName.reserve(N: GV.getName().size() + 1);
470 Mang.getNameWithPrefix(OutName&: MangledName, GV: &GV, /*CannotUsePrivateLabel=*/false);
471 return MustPreserveSymbols.count(Key: MangledName);
472 };
473
474 // Preserve linkonce value on linker request
475 preserveDiscardableGVs(TheModule&: *MergedModule, mustPreserveGV);
476
477 if (!ShouldInternalize)
478 return;
479
480 if (ShouldRestoreGlobalsLinkage) {
481 // Record the linkage type of non-local symbols so they can be restored
482 // prior
483 // to module splitting.
484 auto RecordLinkage = [&](const GlobalValue &GV) {
485 if (!GV.hasAvailableExternallyLinkage() && !GV.hasLocalLinkage() &&
486 GV.hasName())
487 ExternalSymbols.insert(KV: std::make_pair(x: GV.getName(), y: GV.getLinkage()));
488 };
489 for (auto &GV : *MergedModule)
490 RecordLinkage(GV);
491 for (auto &GV : MergedModule->globals())
492 RecordLinkage(GV);
493 for (auto &GV : MergedModule->aliases())
494 RecordLinkage(GV);
495 }
496
497 // Update the llvm.compiler_used globals to force preserving libcalls and
498 // symbols referenced from asm
499 updateCompilerUsed(TheModule&: *MergedModule, TM: *TargetMach, AsmUndefinedRefs);
500
501 internalizeModule(TheModule&: *MergedModule, MustPreserveGV: mustPreserveGV);
502
503 ScopeRestrictionsDone = true;
504}
505
506/// Restore original linkage for symbols that may have been internalized
507void LTOCodeGenerator::restoreLinkageForExternals() {
508 if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage)
509 return;
510
511 assert(ScopeRestrictionsDone &&
512 "Cannot externalize without internalization!");
513
514 if (ExternalSymbols.empty())
515 return;
516
517 auto externalize = [this](GlobalValue &GV) {
518 if (!GV.hasLocalLinkage() || !GV.hasName())
519 return;
520
521 auto I = ExternalSymbols.find(Key: GV.getName());
522 if (I == ExternalSymbols.end())
523 return;
524
525 GV.setLinkage(I->second);
526 };
527
528 llvm::for_each(Range: MergedModule->functions(), F: externalize);
529 llvm::for_each(Range: MergedModule->globals(), F: externalize);
530 llvm::for_each(Range: MergedModule->aliases(), F: externalize);
531}
532
533void LTOCodeGenerator::verifyMergedModuleOnce() {
534 // Only run on the first call.
535 if (HasVerifiedInput)
536 return;
537 HasVerifiedInput = true;
538
539 bool BrokenDebugInfo = false;
540 if (verifyModule(M: *MergedModule, OS: &dbgs(), BrokenDebugInfo: &BrokenDebugInfo))
541 report_fatal_error(reason: "Broken module found, compilation aborted!");
542 if (BrokenDebugInfo) {
543 emitWarning(ErrMsg: "Invalid debug info found, debug info will be stripped");
544 StripDebugInfo(M&: *MergedModule);
545 }
546}
547
548void LTOCodeGenerator::finishOptimizationRemarks() {
549 if (DiagnosticOutputFile) {
550 DiagnosticOutputFile->keep();
551 // FIXME: LTOCodeGenerator dtor is not invoked on Darwin
552 DiagnosticOutputFile->os().flush();
553 }
554}
555
556/// Optimize merged modules using various IPO passes
557bool LTOCodeGenerator::optimize() {
558 if (!this->determineTarget())
559 return false;
560
561 // libLTO parses options late, so re-set them here.
562 Context.setDiscardValueNames(LTODiscardValueNames);
563
564 auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
565 Context, RemarksFilename, RemarksPasses, RemarksFormat,
566 RemarksWithHotness, RemarksHotnessThreshold);
567 if (!DiagFileOrErr) {
568 errs() << "Error: " << toString(E: DiagFileOrErr.takeError()) << "\n";
569 report_fatal_error(reason: "Can't get an output file for the remarks");
570 }
571 DiagnosticOutputFile = std::move(*DiagFileOrErr);
572
573 // Setup output file to emit statistics.
574 auto StatsFileOrErr = lto::setupStatsFile(LTOStatsFile);
575 if (!StatsFileOrErr) {
576 errs() << "Error: " << toString(E: StatsFileOrErr.takeError()) << "\n";
577 report_fatal_error(reason: "Can't get an output file for the statistics");
578 }
579 StatsFile = std::move(StatsFileOrErr.get());
580
581 // Currently there is no support for enabling whole program visibility via a
582 // linker option in the old LTO API, but this call allows it to be specified
583 // via the internal option. Must be done before WPD invoked via the optimizer
584 // pipeline run below.
585 updatePublicTypeTestCalls(M&: *MergedModule,
586 /* WholeProgramVisibilityEnabledInLTO */ false);
587 updateVCallVisibilityInModule(
588 M&: *MergedModule,
589 /* WholeProgramVisibilityEnabledInLTO */ false,
590 // FIXME: These need linker information via a
591 // TBD new interface.
592 /*DynamicExportSymbols=*/{},
593 /*ValidateAllVtablesHaveTypeInfos=*/false,
594 /*IsVisibleToRegularObj=*/[](StringRef) { return true; });
595
596 // We always run the verifier once on the merged module, the `DisableVerify`
597 // parameter only applies to subsequent verify.
598 verifyMergedModuleOnce();
599
600 // Mark which symbols can not be internalized
601 this->applyScopeRestrictions();
602
603 // Add an appropriate DataLayout instance for this module...
604 MergedModule->setDataLayout(TargetMach->createDataLayout());
605
606 if (!SaveIRBeforeOptPath.empty()) {
607 std::error_code EC;
608 raw_fd_ostream OS(SaveIRBeforeOptPath, EC, sys::fs::OF_None);
609 if (EC)
610 report_fatal_error(reason: Twine("Failed to open ") + SaveIRBeforeOptPath +
611 " to save optimized bitcode\n");
612 WriteBitcodeToFile(M: *MergedModule, Out&: OS,
613 /* ShouldPreserveUseListOrder */ true);
614 }
615
616 ModuleSummaryIndex CombinedIndex(false);
617 TargetMach = createTargetMachine();
618 if (!opt(Conf: Config, TM: TargetMach.get(), Task: 0, Mod&: *MergedModule, /*IsThinLTO=*/false,
619 /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
620 /*CmdArgs*/ std::vector<uint8_t>())) {
621 emitError(ErrMsg: "LTO middle-end optimizations failed");
622 return false;
623 }
624
625 return true;
626}
627
628bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream,
629 unsigned ParallelismLevel) {
630 if (!this->determineTarget())
631 return false;
632
633 // We always run the verifier once on the merged module. If it has already
634 // been called in optimize(), this call will return early.
635 verifyMergedModuleOnce();
636
637 // Re-externalize globals that may have been internalized to increase scope
638 // for splitting
639 restoreLinkageForExternals();
640
641 ModuleSummaryIndex CombinedIndex(false);
642
643 Config.CodeGenOnly = true;
644 Error Err = backend(C: Config, AddStream, ParallelCodeGenParallelismLevel: ParallelismLevel, M&: *MergedModule,
645 CombinedIndex);
646 assert(!Err && "unexpected code-generation failure");
647 (void)Err;
648
649 // If statistics were requested, save them to the specified file or
650 // print them out after codegen.
651 if (StatsFile)
652 PrintStatisticsJSON(OS&: StatsFile->os());
653 else if (AreStatisticsEnabled())
654 PrintStatistics();
655
656 reportAndResetTimings();
657
658 finishOptimizationRemarks();
659
660 return true;
661}
662
663void LTOCodeGenerator::setCodeGenDebugOptions(ArrayRef<StringRef> Options) {
664 for (StringRef Option : Options)
665 CodegenOptions.push_back(x: Option.str());
666}
667
668void LTOCodeGenerator::parseCodeGenDebugOptions() {
669 if (!CodegenOptions.empty())
670 llvm::parseCommandLineOptions(Options&: CodegenOptions);
671}
672
673void llvm::parseCommandLineOptions(std::vector<std::string> &Options) {
674 if (!Options.empty()) {
675 // ParseCommandLineOptions() expects argv[0] to be program name.
676 std::vector<const char *> CodegenArgv(1, "libLLVMLTO");
677 for (std::string &Arg : Options)
678 CodegenArgv.push_back(x: Arg.c_str());
679 cl::ParseCommandLineOptions(argc: CodegenArgv.size(), argv: CodegenArgv.data());
680 }
681}
682
683void LTOCodeGenerator::DiagnosticHandler(const DiagnosticInfo &DI) {
684 // Map the LLVM internal diagnostic severity to the LTO diagnostic severity.
685 lto_codegen_diagnostic_severity_t Severity;
686 switch (DI.getSeverity()) {
687 case DS_Error:
688 Severity = LTO_DS_ERROR;
689 break;
690 case DS_Warning:
691 Severity = LTO_DS_WARNING;
692 break;
693 case DS_Remark:
694 Severity = LTO_DS_REMARK;
695 break;
696 case DS_Note:
697 Severity = LTO_DS_NOTE;
698 break;
699 }
700 // Create the string that will be reported to the external diagnostic handler.
701 std::string MsgStorage;
702 raw_string_ostream Stream(MsgStorage);
703 DiagnosticPrinterRawOStream DP(Stream);
704 DI.print(DP);
705 Stream.flush();
706
707 // If this method has been called it means someone has set up an external
708 // diagnostic handler. Assert on that.
709 assert(DiagHandler && "Invalid diagnostic handler");
710 (*DiagHandler)(Severity, MsgStorage.c_str(), DiagContext);
711}
712
713namespace {
714struct LTODiagnosticHandler : public DiagnosticHandler {
715 LTOCodeGenerator *CodeGenerator;
716 LTODiagnosticHandler(LTOCodeGenerator *CodeGenPtr)
717 : CodeGenerator(CodeGenPtr) {}
718 bool handleDiagnostics(const DiagnosticInfo &DI) override {
719 CodeGenerator->DiagnosticHandler(DI);
720 return true;
721 }
722};
723}
724
725void
726LTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_t DiagHandler,
727 void *Ctxt) {
728 this->DiagHandler = DiagHandler;
729 this->DiagContext = Ctxt;
730 if (!DiagHandler)
731 return Context.setDiagnosticHandler(DH: nullptr);
732 // Register the LTOCodeGenerator stub in the LLVMContext to forward the
733 // diagnostic to the external DiagHandler.
734 Context.setDiagnosticHandler(DH: std::make_unique<LTODiagnosticHandler>(args: this),
735 RespectFilters: true);
736}
737
738namespace {
739class LTODiagnosticInfo : public DiagnosticInfo {
740 const Twine &Msg;
741public:
742 LTODiagnosticInfo(const Twine &DiagMsg LLVM_LIFETIME_BOUND,
743 DiagnosticSeverity Severity = DS_Error)
744 : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
745 void print(DiagnosticPrinter &DP) const override { DP << Msg; }
746};
747}
748
749void LTOCodeGenerator::emitError(const std::string &ErrMsg) {
750 if (DiagHandler)
751 (*DiagHandler)(LTO_DS_ERROR, ErrMsg.c_str(), DiagContext);
752 else
753 Context.diagnose(DI: LTODiagnosticInfo(ErrMsg));
754}
755
756void LTOCodeGenerator::emitWarning(const std::string &ErrMsg) {
757 if (DiagHandler)
758 (*DiagHandler)(LTO_DS_WARNING, ErrMsg.c_str(), DiagContext);
759 else
760 Context.diagnose(DI: LTODiagnosticInfo(ErrMsg, DS_Warning));
761}
762

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of llvm/lib/LTO/LTOCodeGenerator.cpp