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