brintos

brintos / llvm-project-archived public Read only

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