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