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