10b57cec5SDimitry Andric //===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the Link Time Optimization library. This library is 100b57cec5SDimitry Andric // intended to be used by linker to optimize code at link time. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/LTO/legacy/LTOCodeGenerator.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 170b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 180b57cec5SDimitry Andric #include "llvm/Analysis/Passes.h" 190b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 200b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 210b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriter.h" 22bdd1243dSDimitry Andric #include "llvm/CodeGen/CommandFlags.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 240b57cec5SDimitry Andric #include "llvm/Config/config.h" 250b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 260b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 270b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h" 280b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 290b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 300b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h" 310b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 325ffd83dbSDimitry Andric #include "llvm/IR/LLVMRemarkStreamer.h" 330b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 340b57cec5SDimitry Andric #include "llvm/IR/Mangler.h" 350b57cec5SDimitry Andric #include "llvm/IR/Module.h" 360b57cec5SDimitry Andric #include "llvm/IR/PassTimingInfo.h" 370b57cec5SDimitry Andric #include "llvm/IR/Verifier.h" 380b57cec5SDimitry Andric #include "llvm/LTO/LTO.h" 39fe6060f1SDimitry Andric #include "llvm/LTO/LTOBackend.h" 400b57cec5SDimitry Andric #include "llvm/LTO/legacy/LTOModule.h" 410b57cec5SDimitry Andric #include "llvm/LTO/legacy/UpdateCompilerUsed.h" 420b57cec5SDimitry Andric #include "llvm/Linker/Linker.h" 430b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 440b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 45349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 46e8d8bef9SDimitry Andric #include "llvm/Remarks/HotnessThresholdParser.h" 470b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 480b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 490b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 50bdd1243dSDimitry Andric #include "llvm/Support/Process.h" 510b57cec5SDimitry Andric #include "llvm/Support/Signals.h" 520b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h" 530b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h" 540b57cec5SDimitry Andric #include "llvm/Support/YAMLTraits.h" 550b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 560b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 5706c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 5806c3fb27SDimitry Andric #include "llvm/TargetParser/SubtargetFeature.h" 590b57cec5SDimitry Andric #include "llvm/Transforms/IPO.h" 600b57cec5SDimitry Andric #include "llvm/Transforms/IPO/Internalize.h" 615ffd83dbSDimitry Andric #include "llvm/Transforms/IPO/WholeProgramDevirt.h" 620b57cec5SDimitry Andric #include "llvm/Transforms/ObjCARC.h" 630b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 64bdd1243dSDimitry Andric #include <optional> 650b57cec5SDimitry Andric #include <system_error> 660b57cec5SDimitry Andric using namespace llvm; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric const char* LTOCodeGenerator::getVersionString() { 690b57cec5SDimitry Andric return PACKAGE_NAME " version " PACKAGE_VERSION; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric namespace llvm { 730b57cec5SDimitry Andric cl::opt<bool> LTODiscardValueNames( 740b57cec5SDimitry Andric "lto-discard-value-names", 750b57cec5SDimitry Andric cl::desc("Strip names from Value during LTO (other than GlobalValue)."), 760b57cec5SDimitry Andric #ifdef NDEBUG 770b57cec5SDimitry Andric cl::init(true), 780b57cec5SDimitry Andric #else 790b57cec5SDimitry Andric cl::init(false), 800b57cec5SDimitry Andric #endif 810b57cec5SDimitry Andric cl::Hidden); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric cl::opt<bool> RemarksWithHotness( 840b57cec5SDimitry Andric "lto-pass-remarks-with-hotness", 850b57cec5SDimitry Andric cl::desc("With PGO, include profile count in optimization remarks"), 860b57cec5SDimitry Andric cl::Hidden); 870b57cec5SDimitry Andric 88bdd1243dSDimitry Andric cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser> 89e8d8bef9SDimitry Andric RemarksHotnessThreshold( 90e8d8bef9SDimitry Andric "lto-pass-remarks-hotness-threshold", 91e8d8bef9SDimitry Andric cl::desc("Minimum profile count required for an " 92e8d8bef9SDimitry Andric "optimization remark to be output." 93e8d8bef9SDimitry Andric " Use 'auto' to apply the threshold from profile summary."), 94e8d8bef9SDimitry Andric cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden); 95e8d8bef9SDimitry Andric 960b57cec5SDimitry Andric cl::opt<std::string> 970b57cec5SDimitry Andric RemarksFilename("lto-pass-remarks-output", 980b57cec5SDimitry Andric cl::desc("Output filename for pass remarks"), 990b57cec5SDimitry Andric cl::value_desc("filename")); 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric cl::opt<std::string> 1020b57cec5SDimitry Andric RemarksPasses("lto-pass-remarks-filter", 1030b57cec5SDimitry Andric cl::desc("Only record optimization remarks from passes whose " 1040b57cec5SDimitry Andric "names match the given regular expression"), 1050b57cec5SDimitry Andric cl::value_desc("regex")); 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric cl::opt<std::string> RemarksFormat( 1080b57cec5SDimitry Andric "lto-pass-remarks-format", 1090b57cec5SDimitry Andric cl::desc("The format used for serializing remarks (default: YAML)"), 1100b57cec5SDimitry Andric cl::value_desc("format"), cl::init("yaml")); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric cl::opt<std::string> LTOStatsFile( 1130b57cec5SDimitry Andric "lto-stats-file", 1140b57cec5SDimitry Andric cl::desc("Save statistics to the specified file"), 1150b57cec5SDimitry Andric cl::Hidden); 116bdd1243dSDimitry Andric 117bdd1243dSDimitry Andric cl::opt<std::string> AIXSystemAssemblerPath( 118bdd1243dSDimitry Andric "lto-aix-system-assembler", 119bdd1243dSDimitry Andric cl::desc("Path to a system assembler, picked up on AIX only"), 120bdd1243dSDimitry Andric cl::value_desc("path")); 121bdd1243dSDimitry Andric 122bdd1243dSDimitry Andric cl::opt<bool> 123bdd1243dSDimitry Andric LTORunCSIRInstr("cs-profile-generate", 124bdd1243dSDimitry Andric cl::desc("Perform context sensitive PGO instrumentation")); 125bdd1243dSDimitry Andric 126bdd1243dSDimitry Andric cl::opt<std::string> 127bdd1243dSDimitry Andric LTOCSIRProfile("cs-profile-path", 128bdd1243dSDimitry Andric cl::desc("Context sensitive profile file path")); 129bdd1243dSDimitry Andric } // namespace llvm 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) 1320b57cec5SDimitry Andric : Context(Context), MergedModule(new Module("ld-temp.o", Context)), 1330b57cec5SDimitry Andric TheLinker(new Linker(*MergedModule)) { 1340b57cec5SDimitry Andric Context.setDiscardValueNames(LTODiscardValueNames); 1350b57cec5SDimitry Andric Context.enableDebugTypeODRUniquing(); 136fe6060f1SDimitry Andric 137bdd1243dSDimitry Andric Config.CodeModel = std::nullopt; 138fe6060f1SDimitry Andric Config.StatsFile = LTOStatsFile; 139fe6060f1SDimitry Andric Config.PreCodeGenPassesHook = [](legacy::PassManager &PM) { 140fe6060f1SDimitry Andric PM.add(createObjCARCContractPass()); 141fe6060f1SDimitry Andric }; 142bdd1243dSDimitry Andric 143bdd1243dSDimitry Andric Config.RunCSIRInstr = LTORunCSIRInstr; 144bdd1243dSDimitry Andric Config.CSIRProfile = LTOCSIRProfile; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 14781ad6265SDimitry Andric LTOCodeGenerator::~LTOCodeGenerator() = default; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) { 1500eae32dcSDimitry Andric for (const StringRef &Undef : Mod->getAsmUndefinedRefs()) 1510eae32dcSDimitry Andric AsmUndefinedRefs.insert(Undef); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric bool LTOCodeGenerator::addModule(LTOModule *Mod) { 1550b57cec5SDimitry Andric assert(&Mod->getModule().getContext() == &Context && 1560b57cec5SDimitry Andric "Expected module in same context"); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ret = TheLinker->linkInModule(Mod->takeModule()); 1590b57cec5SDimitry Andric setAsmUndefinedRefs(Mod); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // We've just changed the input, so let's make sure we verify it. 1620b57cec5SDimitry Andric HasVerifiedInput = false; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric return !ret; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) { 1680b57cec5SDimitry Andric assert(&Mod->getModule().getContext() == &Context && 1690b57cec5SDimitry Andric "Expected module in same context"); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric AsmUndefinedRefs.clear(); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric MergedModule = Mod->takeModule(); 1748bcb0991SDimitry Andric TheLinker = std::make_unique<Linker>(*MergedModule); 1750b57cec5SDimitry Andric setAsmUndefinedRefs(&*Mod); 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric // We've just changed the input, so let's make sure we verify it. 1780b57cec5SDimitry Andric HasVerifiedInput = false; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric void LTOCodeGenerator::setTargetOptions(const TargetOptions &Options) { 182fe6060f1SDimitry Andric Config.Options = Options; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric void LTOCodeGenerator::setDebugInfo(lto_debug_model Debug) { 1860b57cec5SDimitry Andric switch (Debug) { 1870b57cec5SDimitry Andric case LTO_DEBUG_MODEL_NONE: 1880b57cec5SDimitry Andric EmitDwarfDebugInfo = false; 1890b57cec5SDimitry Andric return; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric case LTO_DEBUG_MODEL_DWARF: 1920b57cec5SDimitry Andric EmitDwarfDebugInfo = true; 1930b57cec5SDimitry Andric return; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric llvm_unreachable("Unknown debug format!"); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric void LTOCodeGenerator::setOptLevel(unsigned Level) { 199fe6060f1SDimitry Andric Config.OptLevel = Level; 200fe6060f1SDimitry Andric Config.PTO.LoopVectorization = Config.OptLevel > 1; 201fe6060f1SDimitry Andric Config.PTO.SLPVectorization = Config.OptLevel > 1; 2025f757f3fSDimitry Andric std::optional<CodeGenOptLevel> CGOptLevelOrNone = 203bdd1243dSDimitry Andric CodeGenOpt::getLevel(Config.OptLevel); 204bdd1243dSDimitry Andric assert(CGOptLevelOrNone && "Unknown optimization level!"); 205bdd1243dSDimitry Andric Config.CGOptLevel = *CGOptLevelOrNone; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric bool LTOCodeGenerator::writeMergedModules(StringRef Path) { 2090b57cec5SDimitry Andric if (!determineTarget()) 2100b57cec5SDimitry Andric return false; 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric // We always run the verifier once on the merged module. 2130b57cec5SDimitry Andric verifyMergedModuleOnce(); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // mark which symbols can not be internalized 2160b57cec5SDimitry Andric applyScopeRestrictions(); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric // create output file 2190b57cec5SDimitry Andric std::error_code EC; 2208bcb0991SDimitry Andric ToolOutputFile Out(Path, EC, sys::fs::OF_None); 2210b57cec5SDimitry Andric if (EC) { 2220b57cec5SDimitry Andric std::string ErrMsg = "could not open bitcode file for writing: "; 2230b57cec5SDimitry Andric ErrMsg += Path.str() + ": " + EC.message(); 2240b57cec5SDimitry Andric emitError(ErrMsg); 2250b57cec5SDimitry Andric return false; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric // write bitcode to it 2290b57cec5SDimitry Andric WriteBitcodeToFile(*MergedModule, Out.os(), ShouldEmbedUselists); 2300b57cec5SDimitry Andric Out.os().close(); 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric if (Out.os().has_error()) { 2330b57cec5SDimitry Andric std::string ErrMsg = "could not write bitcode file: "; 2340b57cec5SDimitry Andric ErrMsg += Path.str() + ": " + Out.os().error().message(); 2350b57cec5SDimitry Andric emitError(ErrMsg); 2360b57cec5SDimitry Andric Out.os().clear_error(); 2370b57cec5SDimitry Andric return false; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric Out.keep(); 2410b57cec5SDimitry Andric return true; 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 244bdd1243dSDimitry Andric bool LTOCodeGenerator::useAIXSystemAssembler() { 245bdd1243dSDimitry Andric const auto &Triple = TargetMach->getTargetTriple(); 24606c3fb27SDimitry Andric return Triple.isOSAIX() && Config.Options.DisableIntegratedAS; 247bdd1243dSDimitry Andric } 248bdd1243dSDimitry Andric 249bdd1243dSDimitry Andric bool LTOCodeGenerator::runAIXSystemAssembler(SmallString<128> &AssemblyFile) { 250bdd1243dSDimitry Andric assert(useAIXSystemAssembler() && 251bdd1243dSDimitry Andric "Runing AIX system assembler when integrated assembler is available!"); 252bdd1243dSDimitry Andric 253bdd1243dSDimitry Andric // Set the system assembler path. 254bdd1243dSDimitry Andric SmallString<256> AssemblerPath("/usr/bin/as"); 255bdd1243dSDimitry Andric if (!llvm::AIXSystemAssemblerPath.empty()) { 256bdd1243dSDimitry Andric if (llvm::sys::fs::real_path(llvm::AIXSystemAssemblerPath, AssemblerPath, 257bdd1243dSDimitry Andric /* expand_tilde */ true)) { 258bdd1243dSDimitry Andric emitError( 259bdd1243dSDimitry Andric "Cannot find the assembler specified by lto-aix-system-assembler"); 260bdd1243dSDimitry Andric return false; 261bdd1243dSDimitry Andric } 262bdd1243dSDimitry Andric } 263bdd1243dSDimitry Andric 264bdd1243dSDimitry Andric // Setup the LDR_CNTRL variable 265bdd1243dSDimitry Andric std::string LDR_CNTRL_var = "LDR_CNTRL=MAXDATA32=0xA0000000@DSA"; 266bdd1243dSDimitry Andric if (std::optional<std::string> V = sys::Process::GetEnv("LDR_CNTRL")) 267bdd1243dSDimitry Andric LDR_CNTRL_var += ("@" + *V); 268bdd1243dSDimitry Andric 269bdd1243dSDimitry Andric // Prepare inputs for the assember. 270bdd1243dSDimitry Andric const auto &Triple = TargetMach->getTargetTriple(); 271bdd1243dSDimitry Andric const char *Arch = Triple.isArch64Bit() ? "-a64" : "-a32"; 272bdd1243dSDimitry Andric std::string ObjectFileName(AssemblyFile); 273bdd1243dSDimitry Andric ObjectFileName[ObjectFileName.size() - 1] = 'o'; 274bdd1243dSDimitry Andric SmallVector<StringRef, 8> Args = { 275bdd1243dSDimitry Andric "/bin/env", LDR_CNTRL_var, 276bdd1243dSDimitry Andric AssemblerPath, Arch, 277bdd1243dSDimitry Andric "-many", "-o", 278bdd1243dSDimitry Andric ObjectFileName, AssemblyFile}; 279bdd1243dSDimitry Andric 280bdd1243dSDimitry Andric // Invoke the assembler. 281bdd1243dSDimitry Andric int RC = sys::ExecuteAndWait(Args[0], Args); 282bdd1243dSDimitry Andric 283bdd1243dSDimitry Andric // Handle errors. 284bdd1243dSDimitry Andric if (RC < -1) { 285bdd1243dSDimitry Andric emitError("LTO assembler exited abnormally"); 286bdd1243dSDimitry Andric return false; 287bdd1243dSDimitry Andric } 288bdd1243dSDimitry Andric if (RC < 0) { 289bdd1243dSDimitry Andric emitError("Unable to invoke LTO assembler"); 290bdd1243dSDimitry Andric return false; 291bdd1243dSDimitry Andric } 292bdd1243dSDimitry Andric if (RC > 0) { 293bdd1243dSDimitry Andric emitError("LTO assembler invocation returned non-zero"); 294bdd1243dSDimitry Andric return false; 295bdd1243dSDimitry Andric } 296bdd1243dSDimitry Andric 297bdd1243dSDimitry Andric // Cleanup. 298bdd1243dSDimitry Andric remove(AssemblyFile.c_str()); 299bdd1243dSDimitry Andric 300bdd1243dSDimitry Andric // Fix the output file name. 301bdd1243dSDimitry Andric AssemblyFile = ObjectFileName; 302bdd1243dSDimitry Andric 303bdd1243dSDimitry Andric return true; 304bdd1243dSDimitry Andric } 305bdd1243dSDimitry Andric 3060b57cec5SDimitry Andric bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) { 307bdd1243dSDimitry Andric if (useAIXSystemAssembler()) 3085f757f3fSDimitry Andric setFileType(CodeGenFileType::AssemblyFile); 309bdd1243dSDimitry Andric 3100b57cec5SDimitry Andric // make unique temp output file to put generated code 3110b57cec5SDimitry Andric SmallString<128> Filename; 312fe6060f1SDimitry Andric 313bdd1243dSDimitry Andric auto AddStream = 314bdd1243dSDimitry Andric [&](size_t Task, 315bdd1243dSDimitry Andric const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> { 3165f757f3fSDimitry Andric StringRef Extension( 3175f757f3fSDimitry Andric Config.CGFileType == CodeGenFileType::AssemblyFile ? "s" : "o"); 318fe6060f1SDimitry Andric 3190b57cec5SDimitry Andric int FD; 3200b57cec5SDimitry Andric std::error_code EC = 3210b57cec5SDimitry Andric sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); 322fe6060f1SDimitry Andric if (EC) 3230b57cec5SDimitry Andric emitError(EC.message()); 3240b57cec5SDimitry Andric 325349cc55cSDimitry Andric return std::make_unique<CachedFileStream>( 326fe6060f1SDimitry Andric std::make_unique<llvm::raw_fd_ostream>(FD, true)); 327fe6060f1SDimitry Andric }; 3280b57cec5SDimitry Andric 329fe6060f1SDimitry Andric bool genResult = compileOptimized(AddStream, 1); 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric if (!genResult) { 3320b57cec5SDimitry Andric sys::fs::remove(Twine(Filename)); 3330b57cec5SDimitry Andric return false; 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 336fe6060f1SDimitry Andric // If statistics were requested, save them to the specified file or 337fe6060f1SDimitry Andric // print them out after codegen. 338fe6060f1SDimitry Andric if (StatsFile) 339fe6060f1SDimitry Andric PrintStatisticsJSON(StatsFile->os()); 340fe6060f1SDimitry Andric else if (AreStatisticsEnabled()) 341fe6060f1SDimitry Andric PrintStatistics(); 342fe6060f1SDimitry Andric 343bdd1243dSDimitry Andric if (useAIXSystemAssembler()) 344bdd1243dSDimitry Andric if (!runAIXSystemAssembler(Filename)) 345bdd1243dSDimitry Andric return false; 346bdd1243dSDimitry Andric 3470b57cec5SDimitry Andric NativeObjectPath = Filename.c_str(); 3480b57cec5SDimitry Andric *Name = NativeObjectPath.c_str(); 3490b57cec5SDimitry Andric return true; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 3530b57cec5SDimitry Andric LTOCodeGenerator::compileOptimized() { 3540b57cec5SDimitry Andric const char *name; 3550b57cec5SDimitry Andric if (!compileOptimizedToFile(&name)) 3560b57cec5SDimitry Andric return nullptr; 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric // read .o file into memory buffer 359fe6060f1SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile( 360fe6060f1SDimitry Andric name, /*IsText=*/false, /*RequiresNullTerminator=*/false); 3610b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) { 3620b57cec5SDimitry Andric emitError(EC.message()); 3630b57cec5SDimitry Andric sys::fs::remove(NativeObjectPath); 3640b57cec5SDimitry Andric return nullptr; 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric // remove temp files 3680b57cec5SDimitry Andric sys::fs::remove(NativeObjectPath); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric return std::move(*BufferOrErr); 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 373e8d8bef9SDimitry Andric bool LTOCodeGenerator::compile_to_file(const char **Name) { 374e8d8bef9SDimitry Andric if (!optimize()) 3750b57cec5SDimitry Andric return false; 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric return compileOptimizedToFile(Name); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 380e8d8bef9SDimitry Andric std::unique_ptr<MemoryBuffer> LTOCodeGenerator::compile() { 381e8d8bef9SDimitry Andric if (!optimize()) 3820b57cec5SDimitry Andric return nullptr; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric return compileOptimized(); 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric bool LTOCodeGenerator::determineTarget() { 3880b57cec5SDimitry Andric if (TargetMach) 3890b57cec5SDimitry Andric return true; 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric TripleStr = MergedModule->getTargetTriple(); 3920b57cec5SDimitry Andric if (TripleStr.empty()) { 3930b57cec5SDimitry Andric TripleStr = sys::getDefaultTargetTriple(); 3940b57cec5SDimitry Andric MergedModule->setTargetTriple(TripleStr); 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric llvm::Triple Triple(TripleStr); 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric // create target machine from info for merged modules 3990b57cec5SDimitry Andric std::string ErrMsg; 4000b57cec5SDimitry Andric MArch = TargetRegistry::lookupTarget(TripleStr, ErrMsg); 4010b57cec5SDimitry Andric if (!MArch) { 4020b57cec5SDimitry Andric emitError(ErrMsg); 4030b57cec5SDimitry Andric return false; 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric // Construct LTOModule, hand over ownership of module and target. Use MAttr as 4070b57cec5SDimitry Andric // the default set of features. 408fe6060f1SDimitry Andric SubtargetFeatures Features(join(Config.MAttrs, "")); 4090b57cec5SDimitry Andric Features.getDefaultSubtargetFeatures(Triple); 4100b57cec5SDimitry Andric FeatureStr = Features.getString(); 411*0fca6ea1SDimitry Andric if (Config.CPU.empty()) 412*0fca6ea1SDimitry Andric Config.CPU = lto::getThinLTODefaultCPU(Triple); 4130b57cec5SDimitry Andric 414bdd1243dSDimitry Andric // If data-sections is not explicitly set or unset, set data-sections by 415bdd1243dSDimitry Andric // default to match the behaviour of lld and gold plugin. 416bdd1243dSDimitry Andric if (!codegen::getExplicitDataSections()) 417bdd1243dSDimitry Andric Config.Options.DataSections = true; 418bdd1243dSDimitry Andric 4190b57cec5SDimitry Andric TargetMach = createTargetMachine(); 420e8d8bef9SDimitry Andric assert(TargetMach && "Unable to create target machine"); 421e8d8bef9SDimitry Andric 4220b57cec5SDimitry Andric return true; 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() { 426e8d8bef9SDimitry Andric assert(MArch && "MArch is not set!"); 4270b57cec5SDimitry Andric return std::unique_ptr<TargetMachine>(MArch->createTargetMachine( 428fe6060f1SDimitry Andric TripleStr, Config.CPU, FeatureStr, Config.Options, Config.RelocModel, 429bdd1243dSDimitry Andric std::nullopt, Config.CGOptLevel)); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // If a linkonce global is present in the MustPreserveSymbols, we need to make 4330b57cec5SDimitry Andric // sure we honor this. To force the compiler to not drop it, we add it to the 4340b57cec5SDimitry Andric // "llvm.compiler.used" global. 4350b57cec5SDimitry Andric void LTOCodeGenerator::preserveDiscardableGVs( 4360b57cec5SDimitry Andric Module &TheModule, 4370b57cec5SDimitry Andric llvm::function_ref<bool(const GlobalValue &)> mustPreserveGV) { 4380b57cec5SDimitry Andric std::vector<GlobalValue *> Used; 4390b57cec5SDimitry Andric auto mayPreserveGlobal = [&](GlobalValue &GV) { 4400b57cec5SDimitry Andric if (!GV.isDiscardableIfUnused() || GV.isDeclaration() || 4410b57cec5SDimitry Andric !mustPreserveGV(GV)) 4420b57cec5SDimitry Andric return; 4430b57cec5SDimitry Andric if (GV.hasAvailableExternallyLinkage()) 4440b57cec5SDimitry Andric return emitWarning( 4450b57cec5SDimitry Andric (Twine("Linker asked to preserve available_externally global: '") + 4460b57cec5SDimitry Andric GV.getName() + "'").str()); 4470b57cec5SDimitry Andric if (GV.hasInternalLinkage()) 4480b57cec5SDimitry Andric return emitWarning((Twine("Linker asked to preserve internal global: '") + 4490b57cec5SDimitry Andric GV.getName() + "'").str()); 4500b57cec5SDimitry Andric Used.push_back(&GV); 4510b57cec5SDimitry Andric }; 4520b57cec5SDimitry Andric for (auto &GV : TheModule) 4530b57cec5SDimitry Andric mayPreserveGlobal(GV); 4540b57cec5SDimitry Andric for (auto &GV : TheModule.globals()) 4550b57cec5SDimitry Andric mayPreserveGlobal(GV); 4560b57cec5SDimitry Andric for (auto &GV : TheModule.aliases()) 4570b57cec5SDimitry Andric mayPreserveGlobal(GV); 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric if (Used.empty()) 4600b57cec5SDimitry Andric return; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric appendToCompilerUsed(TheModule, Used); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric void LTOCodeGenerator::applyScopeRestrictions() { 4660b57cec5SDimitry Andric if (ScopeRestrictionsDone) 4670b57cec5SDimitry Andric return; 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric // Declare a callback for the internalize pass that will ask for every 4700b57cec5SDimitry Andric // candidate GlobalValue if it can be internalized or not. 4710b57cec5SDimitry Andric Mangler Mang; 4720b57cec5SDimitry Andric SmallString<64> MangledName; 4730b57cec5SDimitry Andric auto mustPreserveGV = [&](const GlobalValue &GV) -> bool { 4740b57cec5SDimitry Andric // Unnamed globals can't be mangled, but they can't be preserved either. 4750b57cec5SDimitry Andric if (!GV.hasName()) 4760b57cec5SDimitry Andric return false; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // Need to mangle the GV as the "MustPreserveSymbols" StringSet is filled 4790b57cec5SDimitry Andric // with the linker supplied name, which on Darwin includes a leading 4800b57cec5SDimitry Andric // underscore. 4810b57cec5SDimitry Andric MangledName.clear(); 4820b57cec5SDimitry Andric MangledName.reserve(GV.getName().size() + 1); 4830b57cec5SDimitry Andric Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false); 4840b57cec5SDimitry Andric return MustPreserveSymbols.count(MangledName); 4850b57cec5SDimitry Andric }; 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric // Preserve linkonce value on linker request 4880b57cec5SDimitry Andric preserveDiscardableGVs(*MergedModule, mustPreserveGV); 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric if (!ShouldInternalize) 4910b57cec5SDimitry Andric return; 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric if (ShouldRestoreGlobalsLinkage) { 4940b57cec5SDimitry Andric // Record the linkage type of non-local symbols so they can be restored 4950b57cec5SDimitry Andric // prior 4960b57cec5SDimitry Andric // to module splitting. 4970b57cec5SDimitry Andric auto RecordLinkage = [&](const GlobalValue &GV) { 4980b57cec5SDimitry Andric if (!GV.hasAvailableExternallyLinkage() && !GV.hasLocalLinkage() && 4990b57cec5SDimitry Andric GV.hasName()) 5000b57cec5SDimitry Andric ExternalSymbols.insert(std::make_pair(GV.getName(), GV.getLinkage())); 5010b57cec5SDimitry Andric }; 5020b57cec5SDimitry Andric for (auto &GV : *MergedModule) 5030b57cec5SDimitry Andric RecordLinkage(GV); 5040b57cec5SDimitry Andric for (auto &GV : MergedModule->globals()) 5050b57cec5SDimitry Andric RecordLinkage(GV); 5060b57cec5SDimitry Andric for (auto &GV : MergedModule->aliases()) 5070b57cec5SDimitry Andric RecordLinkage(GV); 5080b57cec5SDimitry Andric } 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric // Update the llvm.compiler_used globals to force preserving libcalls and 5110b57cec5SDimitry Andric // symbols referenced from asm 5120b57cec5SDimitry Andric updateCompilerUsed(*MergedModule, *TargetMach, AsmUndefinedRefs); 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric internalizeModule(*MergedModule, mustPreserveGV); 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric ScopeRestrictionsDone = true; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric /// Restore original linkage for symbols that may have been internalized 5200b57cec5SDimitry Andric void LTOCodeGenerator::restoreLinkageForExternals() { 5210b57cec5SDimitry Andric if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage) 5220b57cec5SDimitry Andric return; 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric assert(ScopeRestrictionsDone && 5250b57cec5SDimitry Andric "Cannot externalize without internalization!"); 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric if (ExternalSymbols.empty()) 5280b57cec5SDimitry Andric return; 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric auto externalize = [this](GlobalValue &GV) { 5310b57cec5SDimitry Andric if (!GV.hasLocalLinkage() || !GV.hasName()) 5320b57cec5SDimitry Andric return; 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric auto I = ExternalSymbols.find(GV.getName()); 5350b57cec5SDimitry Andric if (I == ExternalSymbols.end()) 5360b57cec5SDimitry Andric return; 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric GV.setLinkage(I->second); 5390b57cec5SDimitry Andric }; 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric llvm::for_each(MergedModule->functions(), externalize); 5420b57cec5SDimitry Andric llvm::for_each(MergedModule->globals(), externalize); 5430b57cec5SDimitry Andric llvm::for_each(MergedModule->aliases(), externalize); 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric void LTOCodeGenerator::verifyMergedModuleOnce() { 5470b57cec5SDimitry Andric // Only run on the first call. 5480b57cec5SDimitry Andric if (HasVerifiedInput) 5490b57cec5SDimitry Andric return; 5500b57cec5SDimitry Andric HasVerifiedInput = true; 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric bool BrokenDebugInfo = false; 5530b57cec5SDimitry Andric if (verifyModule(*MergedModule, &dbgs(), &BrokenDebugInfo)) 5540b57cec5SDimitry Andric report_fatal_error("Broken module found, compilation aborted!"); 5550b57cec5SDimitry Andric if (BrokenDebugInfo) { 5560b57cec5SDimitry Andric emitWarning("Invalid debug info found, debug info will be stripped"); 5570b57cec5SDimitry Andric StripDebugInfo(*MergedModule); 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric } 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric void LTOCodeGenerator::finishOptimizationRemarks() { 5620b57cec5SDimitry Andric if (DiagnosticOutputFile) { 5630b57cec5SDimitry Andric DiagnosticOutputFile->keep(); 5640b57cec5SDimitry Andric // FIXME: LTOCodeGenerator dtor is not invoked on Darwin 5650b57cec5SDimitry Andric DiagnosticOutputFile->os().flush(); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric } 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric /// Optimize merged modules using various IPO passes 570e8d8bef9SDimitry Andric bool LTOCodeGenerator::optimize() { 5710b57cec5SDimitry Andric if (!this->determineTarget()) 5720b57cec5SDimitry Andric return false; 5730b57cec5SDimitry Andric 574*0fca6ea1SDimitry Andric // libLTO parses options late, so re-set them here. 575*0fca6ea1SDimitry Andric Context.setDiscardValueNames(LTODiscardValueNames); 576*0fca6ea1SDimitry Andric 577e8d8bef9SDimitry Andric auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( 578e8d8bef9SDimitry Andric Context, RemarksFilename, RemarksPasses, RemarksFormat, 579e8d8bef9SDimitry Andric RemarksWithHotness, RemarksHotnessThreshold); 5800b57cec5SDimitry Andric if (!DiagFileOrErr) { 5810b57cec5SDimitry Andric errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; 5820b57cec5SDimitry Andric report_fatal_error("Can't get an output file for the remarks"); 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric DiagnosticOutputFile = std::move(*DiagFileOrErr); 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric // Setup output file to emit statistics. 5870b57cec5SDimitry Andric auto StatsFileOrErr = lto::setupStatsFile(LTOStatsFile); 5880b57cec5SDimitry Andric if (!StatsFileOrErr) { 5890b57cec5SDimitry Andric errs() << "Error: " << toString(StatsFileOrErr.takeError()) << "\n"; 5900b57cec5SDimitry Andric report_fatal_error("Can't get an output file for the statistics"); 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric StatsFile = std::move(StatsFileOrErr.get()); 5930b57cec5SDimitry Andric 5945ffd83dbSDimitry Andric // Currently there is no support for enabling whole program visibility via a 5955ffd83dbSDimitry Andric // linker option in the old LTO API, but this call allows it to be specified 5965ffd83dbSDimitry Andric // via the internal option. Must be done before WPD invoked via the optimizer 5975ffd83dbSDimitry Andric // pipeline run below. 598972a253aSDimitry Andric updatePublicTypeTestCalls(*MergedModule, 599972a253aSDimitry Andric /* WholeProgramVisibilityEnabledInLTO */ false); 6005f757f3fSDimitry Andric updateVCallVisibilityInModule( 6015f757f3fSDimitry Andric *MergedModule, 602fe6060f1SDimitry Andric /* WholeProgramVisibilityEnabledInLTO */ false, 6035f757f3fSDimitry Andric // FIXME: These need linker information via a 604fe6060f1SDimitry Andric // TBD new interface. 6055f757f3fSDimitry Andric /*DynamicExportSymbols=*/{}, 6065f757f3fSDimitry Andric /*ValidateAllVtablesHaveTypeInfos=*/false, 6075f757f3fSDimitry Andric /*IsVisibleToRegularObj=*/[](StringRef) { return true; }); 6085ffd83dbSDimitry Andric 6090b57cec5SDimitry Andric // We always run the verifier once on the merged module, the `DisableVerify` 6100b57cec5SDimitry Andric // parameter only applies to subsequent verify. 6110b57cec5SDimitry Andric verifyMergedModuleOnce(); 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric // Mark which symbols can not be internalized 6140b57cec5SDimitry Andric this->applyScopeRestrictions(); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // Add an appropriate DataLayout instance for this module... 6170b57cec5SDimitry Andric MergedModule->setDataLayout(TargetMach->createDataLayout()); 6180b57cec5SDimitry Andric 619972a253aSDimitry Andric if (!SaveIRBeforeOptPath.empty()) { 620972a253aSDimitry Andric std::error_code EC; 621972a253aSDimitry Andric raw_fd_ostream OS(SaveIRBeforeOptPath, EC, sys::fs::OF_None); 622972a253aSDimitry Andric if (EC) 623972a253aSDimitry Andric report_fatal_error(Twine("Failed to open ") + SaveIRBeforeOptPath + 624972a253aSDimitry Andric " to save optimized bitcode\n"); 625972a253aSDimitry Andric WriteBitcodeToFile(*MergedModule, OS, 626972a253aSDimitry Andric /* ShouldPreserveUseListOrder */ true); 627972a253aSDimitry Andric } 628972a253aSDimitry Andric 629fe6060f1SDimitry Andric ModuleSummaryIndex CombinedIndex(false); 630fe6060f1SDimitry Andric TargetMach = createTargetMachine(); 631fe6060f1SDimitry Andric if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false, 632fe6060f1SDimitry Andric /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, 633fe6060f1SDimitry Andric /*CmdArgs*/ std::vector<uint8_t>())) { 634fe6060f1SDimitry Andric emitError("LTO middle-end optimizations failed"); 635fe6060f1SDimitry Andric return false; 636fe6060f1SDimitry Andric } 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric return true; 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 641349cc55cSDimitry Andric bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream, 642fe6060f1SDimitry Andric unsigned ParallelismLevel) { 6430b57cec5SDimitry Andric if (!this->determineTarget()) 6440b57cec5SDimitry Andric return false; 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric // We always run the verifier once on the merged module. If it has already 6470b57cec5SDimitry Andric // been called in optimize(), this call will return early. 6480b57cec5SDimitry Andric verifyMergedModuleOnce(); 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric // Re-externalize globals that may have been internalized to increase scope 6510b57cec5SDimitry Andric // for splitting 6520b57cec5SDimitry Andric restoreLinkageForExternals(); 6530b57cec5SDimitry Andric 654fe6060f1SDimitry Andric ModuleSummaryIndex CombinedIndex(false); 655fe6060f1SDimitry Andric 656fe6060f1SDimitry Andric Config.CodeGenOnly = true; 657fe6060f1SDimitry Andric Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule, 658fe6060f1SDimitry Andric CombinedIndex); 659fe6060f1SDimitry Andric assert(!Err && "unexpected code-generation failure"); 660fe6060f1SDimitry Andric (void)Err; 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric // If statistics were requested, save them to the specified file or 6630b57cec5SDimitry Andric // print them out after codegen. 6640b57cec5SDimitry Andric if (StatsFile) 6650b57cec5SDimitry Andric PrintStatisticsJSON(StatsFile->os()); 6660b57cec5SDimitry Andric else if (AreStatisticsEnabled()) 6670b57cec5SDimitry Andric PrintStatistics(); 6680b57cec5SDimitry Andric 6690b57cec5SDimitry Andric reportAndResetTimings(); 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric finishOptimizationRemarks(); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric return true; 6740b57cec5SDimitry Andric } 6750b57cec5SDimitry Andric 6765ffd83dbSDimitry Andric void LTOCodeGenerator::setCodeGenDebugOptions(ArrayRef<StringRef> Options) { 677480093f4SDimitry Andric for (StringRef Option : Options) 6785ffd83dbSDimitry Andric CodegenOptions.push_back(Option.str()); 6790b57cec5SDimitry Andric } 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric void LTOCodeGenerator::parseCodeGenDebugOptions() { 682fe6060f1SDimitry Andric if (!CodegenOptions.empty()) 683fe6060f1SDimitry Andric llvm::parseCommandLineOptions(CodegenOptions); 684fe6060f1SDimitry Andric } 685fe6060f1SDimitry Andric 686fe6060f1SDimitry Andric void llvm::parseCommandLineOptions(std::vector<std::string> &Options) { 687fe6060f1SDimitry Andric if (!Options.empty()) { 6880b57cec5SDimitry Andric // ParseCommandLineOptions() expects argv[0] to be program name. 6890b57cec5SDimitry Andric std::vector<const char *> CodegenArgv(1, "libLLVMLTO"); 690fe6060f1SDimitry Andric for (std::string &Arg : Options) 6910b57cec5SDimitry Andric CodegenArgv.push_back(Arg.c_str()); 6920b57cec5SDimitry Andric cl::ParseCommandLineOptions(CodegenArgv.size(), CodegenArgv.data()); 6930b57cec5SDimitry Andric } 6940b57cec5SDimitry Andric } 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric void LTOCodeGenerator::DiagnosticHandler(const DiagnosticInfo &DI) { 6970b57cec5SDimitry Andric // Map the LLVM internal diagnostic severity to the LTO diagnostic severity. 6980b57cec5SDimitry Andric lto_codegen_diagnostic_severity_t Severity; 6990b57cec5SDimitry Andric switch (DI.getSeverity()) { 7000b57cec5SDimitry Andric case DS_Error: 7010b57cec5SDimitry Andric Severity = LTO_DS_ERROR; 7020b57cec5SDimitry Andric break; 7030b57cec5SDimitry Andric case DS_Warning: 7040b57cec5SDimitry Andric Severity = LTO_DS_WARNING; 7050b57cec5SDimitry Andric break; 7060b57cec5SDimitry Andric case DS_Remark: 7070b57cec5SDimitry Andric Severity = LTO_DS_REMARK; 7080b57cec5SDimitry Andric break; 7090b57cec5SDimitry Andric case DS_Note: 7100b57cec5SDimitry Andric Severity = LTO_DS_NOTE; 7110b57cec5SDimitry Andric break; 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric // Create the string that will be reported to the external diagnostic handler. 7140b57cec5SDimitry Andric std::string MsgStorage; 7150b57cec5SDimitry Andric raw_string_ostream Stream(MsgStorage); 7160b57cec5SDimitry Andric DiagnosticPrinterRawOStream DP(Stream); 7170b57cec5SDimitry Andric DI.print(DP); 7180b57cec5SDimitry Andric Stream.flush(); 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric // If this method has been called it means someone has set up an external 7210b57cec5SDimitry Andric // diagnostic handler. Assert on that. 7220b57cec5SDimitry Andric assert(DiagHandler && "Invalid diagnostic handler"); 7230b57cec5SDimitry Andric (*DiagHandler)(Severity, MsgStorage.c_str(), DiagContext); 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric namespace { 7270b57cec5SDimitry Andric struct LTODiagnosticHandler : public DiagnosticHandler { 7280b57cec5SDimitry Andric LTOCodeGenerator *CodeGenerator; 7290b57cec5SDimitry Andric LTODiagnosticHandler(LTOCodeGenerator *CodeGenPtr) 7300b57cec5SDimitry Andric : CodeGenerator(CodeGenPtr) {} 7310b57cec5SDimitry Andric bool handleDiagnostics(const DiagnosticInfo &DI) override { 7320b57cec5SDimitry Andric CodeGenerator->DiagnosticHandler(DI); 7330b57cec5SDimitry Andric return true; 7340b57cec5SDimitry Andric } 7350b57cec5SDimitry Andric }; 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric void 7390b57cec5SDimitry Andric LTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_t DiagHandler, 7400b57cec5SDimitry Andric void *Ctxt) { 7410b57cec5SDimitry Andric this->DiagHandler = DiagHandler; 7420b57cec5SDimitry Andric this->DiagContext = Ctxt; 7430b57cec5SDimitry Andric if (!DiagHandler) 7440b57cec5SDimitry Andric return Context.setDiagnosticHandler(nullptr); 7450b57cec5SDimitry Andric // Register the LTOCodeGenerator stub in the LLVMContext to forward the 7460b57cec5SDimitry Andric // diagnostic to the external DiagHandler. 7478bcb0991SDimitry Andric Context.setDiagnosticHandler(std::make_unique<LTODiagnosticHandler>(this), 7480b57cec5SDimitry Andric true); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric namespace { 7520b57cec5SDimitry Andric class LTODiagnosticInfo : public DiagnosticInfo { 7530b57cec5SDimitry Andric const Twine &Msg; 7540b57cec5SDimitry Andric public: 7550b57cec5SDimitry Andric LTODiagnosticInfo(const Twine &DiagMsg, DiagnosticSeverity Severity=DS_Error) 7560b57cec5SDimitry Andric : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {} 7570b57cec5SDimitry Andric void print(DiagnosticPrinter &DP) const override { DP << Msg; } 7580b57cec5SDimitry Andric }; 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric void LTOCodeGenerator::emitError(const std::string &ErrMsg) { 7620b57cec5SDimitry Andric if (DiagHandler) 7630b57cec5SDimitry Andric (*DiagHandler)(LTO_DS_ERROR, ErrMsg.c_str(), DiagContext); 7640b57cec5SDimitry Andric else 7650b57cec5SDimitry Andric Context.diagnose(LTODiagnosticInfo(ErrMsg)); 7660b57cec5SDimitry Andric } 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric void LTOCodeGenerator::emitWarning(const std::string &ErrMsg) { 7690b57cec5SDimitry Andric if (DiagHandler) 7700b57cec5SDimitry Andric (*DiagHandler)(LTO_DS_WARNING, ErrMsg.c_str(), DiagContext); 7710b57cec5SDimitry Andric else 7720b57cec5SDimitry Andric Context.diagnose(LTODiagnosticInfo(ErrMsg, DS_Warning)); 7730b57cec5SDimitry Andric } 774