|  | //===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file implements the Link Time Optimization library. This library is | 
|  | // intended to be used by linker to optimize code at link time. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/LTO/legacy/LTOCodeGenerator.h" | 
|  |  | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/Analysis/TargetLibraryInfo.h" | 
|  | #include "llvm/Analysis/TargetTransformInfo.h" | 
|  | #include "llvm/Bitcode/BitcodeWriter.h" | 
|  | #include "llvm/CodeGen/CommandFlags.h" | 
|  | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
|  | #include "llvm/Config/config.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/IR/DebugInfo.h" | 
|  | #include "llvm/IR/DerivedTypes.h" | 
|  | #include "llvm/IR/DiagnosticInfo.h" | 
|  | #include "llvm/IR/DiagnosticPrinter.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "llvm/IR/LLVMRemarkStreamer.h" | 
|  | #include "llvm/IR/LegacyPassManager.h" | 
|  | #include "llvm/IR/Mangler.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/IR/PassTimingInfo.h" | 
|  | #include "llvm/IR/Verifier.h" | 
|  | #include "llvm/LTO/LTO.h" | 
|  | #include "llvm/LTO/LTOBackend.h" | 
|  | #include "llvm/LTO/legacy/LTOModule.h" | 
|  | #include "llvm/LTO/legacy/UpdateCompilerUsed.h" | 
|  | #include "llvm/Linker/Linker.h" | 
|  | #include "llvm/MC/TargetRegistry.h" | 
|  | #include "llvm/Remarks/HotnessThresholdParser.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/MemoryBuffer.h" | 
|  | #include "llvm/Support/Process.h" | 
|  | #include "llvm/Support/Signals.h" | 
|  | #include "llvm/Support/ToolOutputFile.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Target/TargetOptions.h" | 
|  | #include "llvm/TargetParser/Host.h" | 
|  | #include "llvm/TargetParser/SubtargetFeature.h" | 
|  | #include "llvm/Transforms/IPO.h" | 
|  | #include "llvm/Transforms/IPO/Internalize.h" | 
|  | #include "llvm/Transforms/IPO/WholeProgramDevirt.h" | 
|  | #include "llvm/Transforms/Utils/ModuleUtils.h" | 
|  | #include <optional> | 
|  | #include <system_error> | 
|  | using namespace llvm; | 
|  |  | 
|  | const char* LTOCodeGenerator::getVersionString() { | 
|  | return PACKAGE_NAME " version " PACKAGE_VERSION; | 
|  | } | 
|  |  | 
|  | namespace llvm { | 
|  | cl::opt<bool> LTODiscardValueNames( | 
|  | "lto-discard-value-names", | 
|  | cl::desc("Strip names from Value during LTO (other than GlobalValue)."), | 
|  | #ifdef NDEBUG | 
|  | cl::init(true), | 
|  | #else | 
|  | cl::init(false), | 
|  | #endif | 
|  | cl::Hidden); | 
|  |  | 
|  | cl::opt<bool> RemarksWithHotness( | 
|  | "lto-pass-remarks-with-hotness", | 
|  | cl::desc("With PGO, include profile count in optimization remarks"), | 
|  | cl::Hidden); | 
|  |  | 
|  | cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser> | 
|  | RemarksHotnessThreshold( | 
|  | "lto-pass-remarks-hotness-threshold", | 
|  | cl::desc("Minimum profile count required for an " | 
|  | "optimization remark to be output." | 
|  | " Use 'auto' to apply the threshold from profile summary."), | 
|  | cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden); | 
|  |  | 
|  | cl::opt<std::string> | 
|  | RemarksFilename("lto-pass-remarks-output", | 
|  | cl::desc("Output filename for pass remarks"), | 
|  | cl::value_desc("filename")); | 
|  |  | 
|  | cl::opt<std::string> | 
|  | RemarksPasses("lto-pass-remarks-filter", | 
|  | cl::desc("Only record optimization remarks from passes whose " | 
|  | "names match the given regular expression"), | 
|  | cl::value_desc("regex")); | 
|  |  | 
|  | cl::opt<std::string> RemarksFormat( | 
|  | "lto-pass-remarks-format", | 
|  | cl::desc("The format used for serializing remarks (default: YAML)"), | 
|  | cl::value_desc("format"), cl::init("yaml")); | 
|  |  | 
|  | static cl::opt<std::string> | 
|  | LTOStatsFile("lto-stats-file", | 
|  | cl::desc("Save statistics to the specified file"), cl::Hidden); | 
|  |  | 
|  | static cl::opt<std::string> AIXSystemAssemblerPath( | 
|  | "lto-aix-system-assembler", | 
|  | cl::desc("Path to a system assembler, picked up on AIX only"), | 
|  | cl::value_desc("path")); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | LTORunCSIRInstr("cs-profile-generate", | 
|  | cl::desc("Perform context sensitive PGO instrumentation")); | 
|  |  | 
|  | static cl::opt<std::string> | 
|  | LTOCSIRProfile("cs-profile-path", | 
|  | cl::desc("Context sensitive profile file path")); | 
|  | } // namespace llvm | 
|  |  | 
|  | LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) | 
|  | : Context(Context), MergedModule(new Module("ld-temp.o", Context)), | 
|  | TheLinker(new Linker(*MergedModule)) { | 
|  | Context.setDiscardValueNames(LTODiscardValueNames); | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  |  | 
|  | Config.CodeModel = std::nullopt; | 
|  | Config.StatsFile = LTOStatsFile; | 
|  | Config.RunCSIRInstr = LTORunCSIRInstr; | 
|  | Config.CSIRProfile = LTOCSIRProfile; | 
|  | } | 
|  |  | 
|  | LTOCodeGenerator::~LTOCodeGenerator() = default; | 
|  |  | 
|  | void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) { | 
|  | AsmUndefinedRefs.insert_range(Mod->getAsmUndefinedRefs()); | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::addModule(LTOModule *Mod) { | 
|  | assert(&Mod->getModule().getContext() == &Context && | 
|  | "Expected module in same context"); | 
|  |  | 
|  | bool ret = TheLinker->linkInModule(Mod->takeModule()); | 
|  | setAsmUndefinedRefs(Mod); | 
|  |  | 
|  | // We've just changed the input, so let's make sure we verify it. | 
|  | HasVerifiedInput = false; | 
|  |  | 
|  | return !ret; | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) { | 
|  | assert(&Mod->getModule().getContext() == &Context && | 
|  | "Expected module in same context"); | 
|  |  | 
|  | AsmUndefinedRefs.clear(); | 
|  |  | 
|  | MergedModule = Mod->takeModule(); | 
|  | TheLinker = std::make_unique<Linker>(*MergedModule); | 
|  | setAsmUndefinedRefs(&*Mod); | 
|  |  | 
|  | // We've just changed the input, so let's make sure we verify it. | 
|  | HasVerifiedInput = false; | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::setTargetOptions(const TargetOptions &Options) { | 
|  | Config.Options = Options; | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::setDebugInfo(lto_debug_model Debug) { | 
|  | switch (Debug) { | 
|  | case LTO_DEBUG_MODEL_NONE: | 
|  | EmitDwarfDebugInfo = false; | 
|  | return; | 
|  |  | 
|  | case LTO_DEBUG_MODEL_DWARF: | 
|  | EmitDwarfDebugInfo = true; | 
|  | return; | 
|  | } | 
|  | llvm_unreachable("Unknown debug format!"); | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::setOptLevel(unsigned Level) { | 
|  | Config.OptLevel = Level; | 
|  | Config.PTO.LoopVectorization = Config.OptLevel > 1; | 
|  | Config.PTO.SLPVectorization = Config.OptLevel > 1; | 
|  | std::optional<CodeGenOptLevel> CGOptLevelOrNone = | 
|  | CodeGenOpt::getLevel(Config.OptLevel); | 
|  | assert(CGOptLevelOrNone && "Unknown optimization level!"); | 
|  | Config.CGOptLevel = *CGOptLevelOrNone; | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::writeMergedModules(StringRef Path) { | 
|  | if (!determineTarget()) | 
|  | return false; | 
|  |  | 
|  | // We always run the verifier once on the merged module. | 
|  | verifyMergedModuleOnce(); | 
|  |  | 
|  | // mark which symbols can not be internalized | 
|  | applyScopeRestrictions(); | 
|  |  | 
|  | // create output file | 
|  | std::error_code EC; | 
|  | ToolOutputFile Out(Path, EC, sys::fs::OF_None); | 
|  | if (EC) { | 
|  | std::string ErrMsg = "could not open bitcode file for writing: "; | 
|  | ErrMsg += Path.str() + ": " + EC.message(); | 
|  | emitError(ErrMsg); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // write bitcode to it | 
|  | WriteBitcodeToFile(*MergedModule, Out.os(), ShouldEmbedUselists); | 
|  | Out.os().close(); | 
|  |  | 
|  | if (Out.os().has_error()) { | 
|  | std::string ErrMsg = "could not write bitcode file: "; | 
|  | ErrMsg += Path.str() + ": " + Out.os().error().message(); | 
|  | emitError(ErrMsg); | 
|  | Out.os().clear_error(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Out.keep(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::useAIXSystemAssembler() { | 
|  | const auto &Triple = TargetMach->getTargetTriple(); | 
|  | return Triple.isOSAIX() && Config.Options.DisableIntegratedAS; | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::runAIXSystemAssembler(SmallString<128> &AssemblyFile) { | 
|  | assert(useAIXSystemAssembler() && | 
|  | "Runing AIX system assembler when integrated assembler is available!"); | 
|  |  | 
|  | // Set the system assembler path. | 
|  | SmallString<256> AssemblerPath("/usr/bin/as"); | 
|  | if (!llvm::AIXSystemAssemblerPath.empty()) { | 
|  | if (llvm::sys::fs::real_path(llvm::AIXSystemAssemblerPath, AssemblerPath, | 
|  | /* expand_tilde */ true)) { | 
|  | emitError( | 
|  | "Cannot find the assembler specified by lto-aix-system-assembler"); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Setup the LDR_CNTRL variable | 
|  | std::string LDR_CNTRL_var = "LDR_CNTRL=MAXDATA32=0xA0000000@DSA"; | 
|  | if (std::optional<std::string> V = sys::Process::GetEnv("LDR_CNTRL")) | 
|  | LDR_CNTRL_var += ("@" + *V); | 
|  |  | 
|  | // Prepare inputs for the assember. | 
|  | const auto &Triple = TargetMach->getTargetTriple(); | 
|  | const char *Arch = Triple.isArch64Bit() ? "-a64" : "-a32"; | 
|  | std::string ObjectFileName(AssemblyFile); | 
|  | ObjectFileName[ObjectFileName.size() - 1] = 'o'; | 
|  | SmallVector<StringRef, 8> Args = { | 
|  | "/bin/env",     LDR_CNTRL_var, | 
|  | AssemblerPath,  Arch, | 
|  | "-many",        "-o", | 
|  | ObjectFileName, AssemblyFile}; | 
|  |  | 
|  | // Invoke the assembler. | 
|  | int RC = sys::ExecuteAndWait(Args[0], Args); | 
|  |  | 
|  | // Handle errors. | 
|  | if (RC < -1) { | 
|  | emitError("LTO assembler exited abnormally"); | 
|  | return false; | 
|  | } | 
|  | if (RC < 0) { | 
|  | emitError("Unable to invoke LTO assembler"); | 
|  | return false; | 
|  | } | 
|  | if (RC > 0) { | 
|  | emitError("LTO assembler invocation returned non-zero"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Cleanup. | 
|  | remove(AssemblyFile.c_str()); | 
|  |  | 
|  | // Fix the output file name. | 
|  | AssemblyFile = ObjectFileName; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) { | 
|  | if (useAIXSystemAssembler()) | 
|  | setFileType(CodeGenFileType::AssemblyFile); | 
|  |  | 
|  | // make unique temp output file to put generated code | 
|  | SmallString<128> Filename; | 
|  |  | 
|  | auto AddStream = | 
|  | [&](size_t Task, | 
|  | const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> { | 
|  | StringRef Extension( | 
|  | Config.CGFileType == CodeGenFileType::AssemblyFile ? "s" : "o"); | 
|  |  | 
|  | int FD; | 
|  | std::error_code EC = | 
|  | sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); | 
|  | if (EC) | 
|  | emitError(EC.message()); | 
|  |  | 
|  | return std::make_unique<CachedFileStream>( | 
|  | std::make_unique<llvm::raw_fd_ostream>(FD, true)); | 
|  | }; | 
|  |  | 
|  | bool genResult = compileOptimized(AddStream, 1); | 
|  |  | 
|  | if (!genResult) { | 
|  | sys::fs::remove(Twine(Filename)); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // If statistics were requested, save them to the specified file or | 
|  | // print them out after codegen. | 
|  | if (StatsFile) | 
|  | PrintStatisticsJSON(StatsFile->os()); | 
|  | else if (AreStatisticsEnabled()) | 
|  | PrintStatistics(); | 
|  |  | 
|  | if (useAIXSystemAssembler()) | 
|  | if (!runAIXSystemAssembler(Filename)) | 
|  | return false; | 
|  |  | 
|  | NativeObjectPath = Filename.c_str(); | 
|  | *Name = NativeObjectPath.c_str(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<MemoryBuffer> | 
|  | LTOCodeGenerator::compileOptimized() { | 
|  | const char *name; | 
|  | if (!compileOptimizedToFile(&name)) | 
|  | return nullptr; | 
|  |  | 
|  | // read .o file into memory buffer | 
|  | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile( | 
|  | name, /*IsText=*/false, /*RequiresNullTerminator=*/false); | 
|  | if (std::error_code EC = BufferOrErr.getError()) { | 
|  | emitError(EC.message()); | 
|  | sys::fs::remove(NativeObjectPath); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // remove temp files | 
|  | sys::fs::remove(NativeObjectPath); | 
|  |  | 
|  | return std::move(*BufferOrErr); | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::compile_to_file(const char **Name) { | 
|  | if (!optimize()) | 
|  | return false; | 
|  |  | 
|  | return compileOptimizedToFile(Name); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<MemoryBuffer> LTOCodeGenerator::compile() { | 
|  | if (!optimize()) | 
|  | return nullptr; | 
|  |  | 
|  | return compileOptimized(); | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::determineTarget() { | 
|  | if (TargetMach) | 
|  | return true; | 
|  |  | 
|  | TripleStr = MergedModule->getTargetTriple().str(); | 
|  | llvm::Triple Triple(TripleStr); | 
|  | if (TripleStr.empty()) { | 
|  | TripleStr = sys::getDefaultTargetTriple(); | 
|  | MergedModule->setTargetTriple(Triple); | 
|  | } | 
|  |  | 
|  | // create target machine from info for merged modules | 
|  | std::string ErrMsg; | 
|  | MArch = TargetRegistry::lookupTarget(TripleStr, ErrMsg); | 
|  | if (!MArch) { | 
|  | emitError(ErrMsg); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Construct LTOModule, hand over ownership of module and target. Use MAttr as | 
|  | // the default set of features. | 
|  | SubtargetFeatures Features(join(Config.MAttrs, "")); | 
|  | Features.getDefaultSubtargetFeatures(Triple); | 
|  | FeatureStr = Features.getString(); | 
|  | if (Config.CPU.empty()) | 
|  | Config.CPU = lto::getThinLTODefaultCPU(Triple); | 
|  |  | 
|  | // If data-sections is not explicitly set or unset, set data-sections by | 
|  | // default to match the behaviour of lld and gold plugin. | 
|  | if (!codegen::getExplicitDataSections()) | 
|  | Config.Options.DataSections = true; | 
|  |  | 
|  | TargetMach = createTargetMachine(); | 
|  | assert(TargetMach && "Unable to create target machine"); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() { | 
|  | assert(MArch && "MArch is not set!"); | 
|  | return std::unique_ptr<TargetMachine>(MArch->createTargetMachine( | 
|  | Triple(TripleStr), Config.CPU, FeatureStr, Config.Options, | 
|  | Config.RelocModel, std::nullopt, Config.CGOptLevel)); | 
|  | } | 
|  |  | 
|  | // If a linkonce global is present in the MustPreserveSymbols, we need to make | 
|  | // sure we honor this. To force the compiler to not drop it, we add it to the | 
|  | // "llvm.compiler.used" global. | 
|  | void LTOCodeGenerator::preserveDiscardableGVs( | 
|  | Module &TheModule, | 
|  | llvm::function_ref<bool(const GlobalValue &)> mustPreserveGV) { | 
|  | std::vector<GlobalValue *> Used; | 
|  | auto mayPreserveGlobal = [&](GlobalValue &GV) { | 
|  | if (!GV.isDiscardableIfUnused() || GV.isDeclaration() || | 
|  | !mustPreserveGV(GV)) | 
|  | return; | 
|  | if (GV.hasAvailableExternallyLinkage()) | 
|  | return emitWarning( | 
|  | (Twine("Linker asked to preserve available_externally global: '") + | 
|  | GV.getName() + "'").str()); | 
|  | if (GV.hasInternalLinkage()) | 
|  | return emitWarning((Twine("Linker asked to preserve internal global: '") + | 
|  | GV.getName() + "'").str()); | 
|  | Used.push_back(&GV); | 
|  | }; | 
|  | for (auto &GV : TheModule) | 
|  | mayPreserveGlobal(GV); | 
|  | for (auto &GV : TheModule.globals()) | 
|  | mayPreserveGlobal(GV); | 
|  | for (auto &GV : TheModule.aliases()) | 
|  | mayPreserveGlobal(GV); | 
|  |  | 
|  | if (Used.empty()) | 
|  | return; | 
|  |  | 
|  | appendToCompilerUsed(TheModule, Used); | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::applyScopeRestrictions() { | 
|  | if (ScopeRestrictionsDone) | 
|  | return; | 
|  |  | 
|  | // Declare a callback for the internalize pass that will ask for every | 
|  | // candidate GlobalValue if it can be internalized or not. | 
|  | Mangler Mang; | 
|  | SmallString<64> MangledName; | 
|  | auto mustPreserveGV = [&](const GlobalValue &GV) -> bool { | 
|  | // Unnamed globals can't be mangled, but they can't be preserved either. | 
|  | if (!GV.hasName()) | 
|  | return false; | 
|  |  | 
|  | // Need to mangle the GV as the "MustPreserveSymbols" StringSet is filled | 
|  | // with the linker supplied name, which on Darwin includes a leading | 
|  | // underscore. | 
|  | MangledName.clear(); | 
|  | MangledName.reserve(GV.getName().size() + 1); | 
|  | Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false); | 
|  | return MustPreserveSymbols.count(MangledName); | 
|  | }; | 
|  |  | 
|  | // Preserve linkonce value on linker request | 
|  | preserveDiscardableGVs(*MergedModule, mustPreserveGV); | 
|  |  | 
|  | if (!ShouldInternalize) | 
|  | return; | 
|  |  | 
|  | if (ShouldRestoreGlobalsLinkage) { | 
|  | // Record the linkage type of non-local symbols so they can be restored | 
|  | // prior | 
|  | // to module splitting. | 
|  | auto RecordLinkage = [&](const GlobalValue &GV) { | 
|  | if (!GV.hasAvailableExternallyLinkage() && !GV.hasLocalLinkage() && | 
|  | GV.hasName()) | 
|  | ExternalSymbols.insert(std::make_pair(GV.getName(), GV.getLinkage())); | 
|  | }; | 
|  | for (auto &GV : *MergedModule) | 
|  | RecordLinkage(GV); | 
|  | for (auto &GV : MergedModule->globals()) | 
|  | RecordLinkage(GV); | 
|  | for (auto &GV : MergedModule->aliases()) | 
|  | RecordLinkage(GV); | 
|  | } | 
|  |  | 
|  | // Update the llvm.compiler_used globals to force preserving libcalls and | 
|  | // symbols referenced from asm | 
|  | updateCompilerUsed(*MergedModule, *TargetMach, AsmUndefinedRefs); | 
|  |  | 
|  | internalizeModule(*MergedModule, mustPreserveGV); | 
|  |  | 
|  | ScopeRestrictionsDone = true; | 
|  | } | 
|  |  | 
|  | /// Restore original linkage for symbols that may have been internalized | 
|  | void LTOCodeGenerator::restoreLinkageForExternals() { | 
|  | if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage) | 
|  | return; | 
|  |  | 
|  | assert(ScopeRestrictionsDone && | 
|  | "Cannot externalize without internalization!"); | 
|  |  | 
|  | if (ExternalSymbols.empty()) | 
|  | return; | 
|  |  | 
|  | auto externalize = [this](GlobalValue &GV) { | 
|  | if (!GV.hasLocalLinkage() || !GV.hasName()) | 
|  | return; | 
|  |  | 
|  | auto I = ExternalSymbols.find(GV.getName()); | 
|  | if (I == ExternalSymbols.end()) | 
|  | return; | 
|  |  | 
|  | GV.setLinkage(I->second); | 
|  | }; | 
|  |  | 
|  | llvm::for_each(MergedModule->functions(), externalize); | 
|  | llvm::for_each(MergedModule->globals(), externalize); | 
|  | llvm::for_each(MergedModule->aliases(), externalize); | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::verifyMergedModuleOnce() { | 
|  | // Only run on the first call. | 
|  | if (HasVerifiedInput) | 
|  | return; | 
|  | HasVerifiedInput = true; | 
|  |  | 
|  | bool BrokenDebugInfo = false; | 
|  | if (verifyModule(*MergedModule, &dbgs(), &BrokenDebugInfo)) | 
|  | report_fatal_error("Broken module found, compilation aborted!"); | 
|  | if (BrokenDebugInfo) { | 
|  | emitWarning("Invalid debug info found, debug info will be stripped"); | 
|  | StripDebugInfo(*MergedModule); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::finishOptimizationRemarks() { | 
|  | if (DiagnosticOutputFile) { | 
|  | DiagnosticOutputFile->keep(); | 
|  | // FIXME: LTOCodeGenerator dtor is not invoked on Darwin | 
|  | DiagnosticOutputFile->os().flush(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Optimize merged modules using various IPO passes | 
|  | bool LTOCodeGenerator::optimize() { | 
|  | if (!this->determineTarget()) | 
|  | return false; | 
|  |  | 
|  | // libLTO parses options late, so re-set them here. | 
|  | Context.setDiscardValueNames(LTODiscardValueNames); | 
|  |  | 
|  | auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( | 
|  | Context, RemarksFilename, RemarksPasses, RemarksFormat, | 
|  | RemarksWithHotness, RemarksHotnessThreshold); | 
|  | if (!DiagFileOrErr) { | 
|  | errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; | 
|  | report_fatal_error("Can't get an output file for the remarks"); | 
|  | } | 
|  | DiagnosticOutputFile = std::move(*DiagFileOrErr); | 
|  |  | 
|  | // Setup output file to emit statistics. | 
|  | auto StatsFileOrErr = lto::setupStatsFile(LTOStatsFile); | 
|  | if (!StatsFileOrErr) { | 
|  | errs() << "Error: " << toString(StatsFileOrErr.takeError()) << "\n"; | 
|  | report_fatal_error("Can't get an output file for the statistics"); | 
|  | } | 
|  | StatsFile = std::move(StatsFileOrErr.get()); | 
|  |  | 
|  | // Currently there is no support for enabling whole program visibility via a | 
|  | // linker option in the old LTO API, but this call allows it to be specified | 
|  | // via the internal option. Must be done before WPD invoked via the optimizer | 
|  | // pipeline run below. | 
|  | updatePublicTypeTestCalls(*MergedModule, | 
|  | /* WholeProgramVisibilityEnabledInLTO */ false); | 
|  | updateVCallVisibilityInModule( | 
|  | *MergedModule, | 
|  | /* WholeProgramVisibilityEnabledInLTO */ false, | 
|  | // FIXME: These need linker information via a | 
|  | // TBD new interface. | 
|  | /*DynamicExportSymbols=*/{}, | 
|  | /*ValidateAllVtablesHaveTypeInfos=*/false, | 
|  | /*IsVisibleToRegularObj=*/[](StringRef) { return true; }); | 
|  |  | 
|  | // We always run the verifier once on the merged module, the `DisableVerify` | 
|  | // parameter only applies to subsequent verify. | 
|  | verifyMergedModuleOnce(); | 
|  |  | 
|  | // Mark which symbols can not be internalized | 
|  | this->applyScopeRestrictions(); | 
|  |  | 
|  | // Add an appropriate DataLayout instance for this module... | 
|  | MergedModule->setDataLayout(TargetMach->createDataLayout()); | 
|  |  | 
|  | if (!SaveIRBeforeOptPath.empty()) { | 
|  | std::error_code EC; | 
|  | raw_fd_ostream OS(SaveIRBeforeOptPath, EC, sys::fs::OF_None); | 
|  | if (EC) | 
|  | report_fatal_error(Twine("Failed to open ") + SaveIRBeforeOptPath + | 
|  | " to save optimized bitcode\n"); | 
|  | WriteBitcodeToFile(*MergedModule, OS, | 
|  | /* ShouldPreserveUseListOrder */ true); | 
|  | } | 
|  |  | 
|  | ModuleSummaryIndex CombinedIndex(false); | 
|  | TargetMach = createTargetMachine(); | 
|  | if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false, | 
|  | /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, | 
|  | /*CmdArgs*/ std::vector<uint8_t>())) { | 
|  | emitError("LTO middle-end optimizations failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream, | 
|  | unsigned ParallelismLevel) { | 
|  | if (!this->determineTarget()) | 
|  | return false; | 
|  |  | 
|  | // We always run the verifier once on the merged module.  If it has already | 
|  | // been called in optimize(), this call will return early. | 
|  | verifyMergedModuleOnce(); | 
|  |  | 
|  | // Re-externalize globals that may have been internalized to increase scope | 
|  | // for splitting | 
|  | restoreLinkageForExternals(); | 
|  |  | 
|  | ModuleSummaryIndex CombinedIndex(false); | 
|  |  | 
|  | Config.CodeGenOnly = true; | 
|  | Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule, | 
|  | CombinedIndex); | 
|  | assert(!Err && "unexpected code-generation failure"); | 
|  | (void)Err; | 
|  |  | 
|  | // If statistics were requested, save them to the specified file or | 
|  | // print them out after codegen. | 
|  | if (StatsFile) | 
|  | PrintStatisticsJSON(StatsFile->os()); | 
|  | else if (AreStatisticsEnabled()) | 
|  | PrintStatistics(); | 
|  |  | 
|  | reportAndResetTimings(); | 
|  |  | 
|  | finishOptimizationRemarks(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::setCodeGenDebugOptions(ArrayRef<StringRef> Options) { | 
|  | for (StringRef Option : Options) | 
|  | CodegenOptions.push_back(Option.str()); | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::parseCodeGenDebugOptions() { | 
|  | if (!CodegenOptions.empty()) | 
|  | llvm::parseCommandLineOptions(CodegenOptions); | 
|  | } | 
|  |  | 
|  | void llvm::parseCommandLineOptions(std::vector<std::string> &Options) { | 
|  | if (!Options.empty()) { | 
|  | // ParseCommandLineOptions() expects argv[0] to be program name. | 
|  | std::vector<const char *> CodegenArgv(1, "libLLVMLTO"); | 
|  | for (std::string &Arg : Options) | 
|  | CodegenArgv.push_back(Arg.c_str()); | 
|  | cl::ParseCommandLineOptions(CodegenArgv.size(), CodegenArgv.data()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::DiagnosticHandler(const DiagnosticInfo &DI) { | 
|  | // Map the LLVM internal diagnostic severity to the LTO diagnostic severity. | 
|  | lto_codegen_diagnostic_severity_t Severity; | 
|  | switch (DI.getSeverity()) { | 
|  | case DS_Error: | 
|  | Severity = LTO_DS_ERROR; | 
|  | break; | 
|  | case DS_Warning: | 
|  | Severity = LTO_DS_WARNING; | 
|  | break; | 
|  | case DS_Remark: | 
|  | Severity = LTO_DS_REMARK; | 
|  | break; | 
|  | case DS_Note: | 
|  | Severity = LTO_DS_NOTE; | 
|  | break; | 
|  | } | 
|  | // Create the string that will be reported to the external diagnostic handler. | 
|  | std::string MsgStorage; | 
|  | raw_string_ostream Stream(MsgStorage); | 
|  | DiagnosticPrinterRawOStream DP(Stream); | 
|  | DI.print(DP); | 
|  | Stream.flush(); | 
|  |  | 
|  | // If this method has been called it means someone has set up an external | 
|  | // diagnostic handler. Assert on that. | 
|  | assert(DiagHandler && "Invalid diagnostic handler"); | 
|  | (*DiagHandler)(Severity, MsgStorage.c_str(), DiagContext); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | struct LTODiagnosticHandler : public DiagnosticHandler { | 
|  | LTOCodeGenerator *CodeGenerator; | 
|  | LTODiagnosticHandler(LTOCodeGenerator *CodeGenPtr) | 
|  | : CodeGenerator(CodeGenPtr) {} | 
|  | bool handleDiagnostics(const DiagnosticInfo &DI) override { | 
|  | CodeGenerator->DiagnosticHandler(DI); | 
|  | return true; | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | void | 
|  | LTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_t DiagHandler, | 
|  | void *Ctxt) { | 
|  | this->DiagHandler = DiagHandler; | 
|  | this->DiagContext = Ctxt; | 
|  | if (!DiagHandler) | 
|  | return Context.setDiagnosticHandler(nullptr); | 
|  | // Register the LTOCodeGenerator stub in the LLVMContext to forward the | 
|  | // diagnostic to the external DiagHandler. | 
|  | Context.setDiagnosticHandler(std::make_unique<LTODiagnosticHandler>(this), | 
|  | true); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | class LTODiagnosticInfo : public DiagnosticInfo { | 
|  | const Twine &Msg; | 
|  | public: | 
|  | LTODiagnosticInfo(const Twine &DiagMsg LLVM_LIFETIME_BOUND, | 
|  | DiagnosticSeverity Severity = DS_Error) | 
|  | : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {} | 
|  | void print(DiagnosticPrinter &DP) const override { DP << Msg; } | 
|  | }; | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::emitError(const std::string &ErrMsg) { | 
|  | if (DiagHandler) | 
|  | (*DiagHandler)(LTO_DS_ERROR, ErrMsg.c_str(), DiagContext); | 
|  | else | 
|  | Context.diagnose(LTODiagnosticInfo(ErrMsg)); | 
|  | } | 
|  |  | 
|  | void LTOCodeGenerator::emitWarning(const std::string &ErrMsg) { | 
|  | if (DiagHandler) | 
|  | (*DiagHandler)(LTO_DS_WARNING, ErrMsg.c_str(), DiagContext); | 
|  | else | 
|  | Context.diagnose(LTODiagnosticInfo(ErrMsg, DS_Warning)); | 
|  | } |