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