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