brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.4 KiB · 80c6d24 Raw
425 lines · cpp
1//===- LTO.cpp ------------------------------------------------------------===//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#include "LTO.h"10#include "Config.h"11#include "InputFiles.h"12#include "SymbolTable.h"13#include "Symbols.h"14#include "lld/Common/ErrorHandler.h"15#include "lld/Common/Filesystem.h"16#include "lld/Common/Strings.h"17#include "lld/Common/TargetOptionsCommandFlags.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/ADT/Twine.h"20#include "llvm/BinaryFormat/ELF.h"21#include "llvm/Bitcode/BitcodeWriter.h"22#include "llvm/LTO/Config.h"23#include "llvm/LTO/LTO.h"24#include "llvm/Support/Caching.h"25#include "llvm/Support/CodeGen.h"26#include "llvm/Support/MemoryBuffer.h"27#include "llvm/Support/Path.h"28#include <cstddef>29#include <memory>30#include <string>31#include <system_error>32#include <vector>33 34using namespace llvm;35using namespace llvm::object;36using namespace llvm::ELF;37using namespace lld;38using namespace lld::elf;39 40static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) {41  return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld,42                                   ctx.arg.thinLTOPrefixReplaceNew);43}44 45static lto::Config createConfig(Ctx &ctx) {46  lto::Config c;47 48  // LLD supports the new relocations and address-significance tables.49  c.Options = initTargetOptionsFromCodeGenFlags();50  c.Options.EmitAddrsig = true;51  for (StringRef C : ctx.arg.mllvmOpts)52    c.MllvmArgs.emplace_back(C.str());53 54  // Always emit a section per function/datum with LTO.55  c.Options.FunctionSections = true;56  c.Options.DataSections = true;57 58  // Check if basic block sections must be used.59  // Allowed values for --lto-basic-block-sections are "all",60  // "<file name specifying basic block ids>", or none.  This is the equivalent61  // of -fbasic-block-sections= flag in clang.62  if (!ctx.arg.ltoBasicBlockSections.empty()) {63    if (ctx.arg.ltoBasicBlockSections == "all") {64      c.Options.BBSections = BasicBlockSection::All;65    } else if (ctx.arg.ltoBasicBlockSections == "labels") {66      c.Options.BBAddrMap = true;67      Warn(ctx)68          << "'--lto-basic-block-sections=labels' is deprecated; Please use "69             "'--lto-basic-block-address-map' instead";70    } else if (ctx.arg.ltoBasicBlockSections == "none") {71      c.Options.BBSections = BasicBlockSection::None;72    } else {73      ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =74          MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str());75      if (!MBOrErr) {76        ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections << ":"77                       << MBOrErr.getError().message();78      } else {79        c.Options.BBSectionsFuncListBuf = std::move(*MBOrErr);80      }81      c.Options.BBSections = BasicBlockSection::List;82    }83  }84 85  c.Options.BBAddrMap = ctx.arg.ltoBBAddrMap;86 87  c.Options.UniqueBasicBlockSectionNames =88      ctx.arg.ltoUniqueBasicBlockSectionNames;89 90  if (auto relocModel = getRelocModelFromCMModel())91    c.RelocModel = *relocModel;92  else if (ctx.arg.relocatable)93    c.RelocModel = std::nullopt;94  else if (ctx.arg.isPic)95    c.RelocModel = Reloc::PIC_;96  else97    c.RelocModel = Reloc::Static;98 99  c.CodeModel = getCodeModelFromCMModel();100  c.DisableVerify = ctx.arg.disableVerify;101  c.DiagHandler = diagnosticHandler;102  c.OptLevel = ctx.arg.ltoo;103  c.CPU = getCPUStr();104  c.MAttrs = getMAttrs();105  c.CGOptLevel = ctx.arg.ltoCgo;106 107  c.PTO.LoopVectorization = c.OptLevel > 1;108  c.PTO.SLPVectorization = c.OptLevel > 1;109 110  // Set up a custom pipeline if we've been asked to.111  c.OptPipeline = std::string(ctx.arg.ltoNewPmPasses);112  c.AAPipeline = std::string(ctx.arg.ltoAAPipeline);113 114  // Set up optimization remarks if we've been asked to.115  c.RemarksFilename = std::string(ctx.arg.optRemarksFilename);116  c.RemarksPasses = std::string(ctx.arg.optRemarksPasses);117  c.RemarksWithHotness = ctx.arg.optRemarksWithHotness;118  c.RemarksHotnessThreshold = ctx.arg.optRemarksHotnessThreshold;119  c.RemarksFormat = std::string(ctx.arg.optRemarksFormat);120 121  // Set up output file to emit statistics.122  c.StatsFile = std::string(ctx.arg.optStatsFilename);123 124  c.SampleProfile = std::string(ctx.arg.ltoSampleProfile);125  for (StringRef pluginFn : ctx.arg.passPlugins)126    c.PassPlugins.push_back(std::string(pluginFn));127  c.DebugPassManager = ctx.arg.ltoDebugPassManager;128  c.DwoDir = std::string(ctx.arg.dwoDir);129 130  c.HasWholeProgramVisibility = ctx.arg.ltoWholeProgramVisibility;131  c.ValidateAllVtablesHaveTypeInfos =132      ctx.arg.ltoValidateAllVtablesHaveTypeInfos;133  c.AllVtablesHaveTypeInfos = ctx.ltoAllVtablesHaveTypeInfos;134  c.AlwaysEmitRegularLTOObj = !ctx.arg.ltoObjPath.empty();135  c.KeepSymbolNameCopies = false;136 137  for (const llvm::StringRef &name : ctx.arg.thinLTOModulesToCompile)138    c.ThinLTOModulesToCompile.emplace_back(name);139 140  c.TimeTraceEnabled = ctx.arg.timeTraceEnabled;141  c.TimeTraceGranularity = ctx.arg.timeTraceGranularity;142 143  c.CSIRProfile = std::string(ctx.arg.ltoCSProfileFile);144  c.RunCSIRInstr = ctx.arg.ltoCSProfileGenerate;145  c.PGOWarnMismatch = ctx.arg.ltoPGOWarnMismatch;146 147  if (ctx.arg.emitLLVM) {148    c.PreCodeGenModuleHook = [&ctx](size_t task, const Module &m) {149      if (std::unique_ptr<raw_fd_ostream> os =150              openLTOOutputFile(ctx.arg.outputFile))151        WriteBitcodeToFile(m, *os, false);152      return false;153    };154  }155 156  if (ctx.arg.ltoEmitAsm) {157    c.CGFileType = CodeGenFileType::AssemblyFile;158    c.Options.MCOptions.AsmVerbose = true;159  }160 161  if (!ctx.arg.saveTempsArgs.empty())162    checkError(ctx.e, c.addSaveTemps(ctx.arg.outputFile.str() + ".",163                                     /*UseInputModulePath*/ true,164                                     ctx.arg.saveTempsArgs));165  return c;166}167 168BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {169  // Initialize indexFile.170  if (!ctx.arg.thinLTOIndexOnlyArg.empty())171    indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg);172 173  // Initialize ltoObj.174  lto::ThinBackend backend;175  auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); };176  if (ctx.arg.thinLTOIndexOnly) {177    backend = lto::createWriteIndexesThinBackend(178        llvm::hardware_concurrency(ctx.arg.thinLTOJobs),179        std::string(ctx.arg.thinLTOPrefixReplaceOld),180        std::string(ctx.arg.thinLTOPrefixReplaceNew),181        std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),182        ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);183  } else if (!ctx.arg.dtltoDistributor.empty()) {184    backend = lto::createOutOfProcessThinBackend(185        llvm::hardware_concurrency(ctx.arg.thinLTOJobs), onIndexWrite,186        ctx.arg.thinLTOEmitIndexFiles, ctx.arg.thinLTOEmitImportsFiles,187        ctx.arg.outputFile, ctx.arg.dtltoDistributor,188        ctx.arg.dtltoDistributorArgs, ctx.arg.dtltoCompiler,189        ctx.arg.dtltoCompilerPrependArgs, ctx.arg.dtltoCompilerArgs,190        !ctx.arg.saveTempsArgs.empty());191  } else {192    backend = lto::createInProcessThinBackend(193        llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs),194        onIndexWrite, ctx.arg.thinLTOEmitIndexFiles,195        ctx.arg.thinLTOEmitImportsFiles);196  }197 198  constexpr llvm::lto::LTO::LTOKind ltoModes[3] =199    {llvm::lto::LTO::LTOKind::LTOK_UnifiedThin,200     llvm::lto::LTO::LTOKind::LTOK_UnifiedRegular,201     llvm::lto::LTO::LTOKind::LTOK_Default};202  ltoObj = std::make_unique<lto::LTO>(createConfig(ctx), backend,203                                      ctx.arg.ltoPartitions,204                                      ltoModes[ctx.arg.ltoKind]);205 206  // Initialize usedStartStop.207  if (ctx.bitcodeFiles.empty())208    return;209  for (Symbol *sym : ctx.symtab->getSymbols()) {210    if (sym->isPlaceholder())211      continue;212    StringRef s = sym->getName();213    for (StringRef prefix : {"__start_", "__stop_"})214      if (s.starts_with(prefix))215        usedStartStop.insert(s.substr(prefix.size()));216  }217}218 219BitcodeCompiler::~BitcodeCompiler() = default;220 221void BitcodeCompiler::add(BitcodeFile &f) {222  lto::InputFile &obj = *f.obj;223  bool isExec = !ctx.arg.shared && !ctx.arg.relocatable;224 225  if (ctx.arg.thinLTOEmitIndexFiles)226    thinIndices.insert(obj.getName());227 228  ArrayRef<Symbol *> syms = f.getSymbols();229  ArrayRef<lto::InputFile::Symbol> objSyms = obj.symbols();230  std::vector<lto::SymbolResolution> resols(syms.size());231 232  // Provide a resolution to the LTO API for each symbol.233  for (size_t i = 0, e = syms.size(); i != e; ++i) {234    Symbol *sym = syms[i];235    const lto::InputFile::Symbol &objSym = objSyms[i];236    lto::SymbolResolution &r = resols[i];237 238    // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile239    // reports two symbols for module ASM defined. Without this check, lld240    // flags an undefined in IR with a definition in ASM as prevailing.241    // Once IRObjectFile is fixed to report only one symbol this hack can242    // be removed.243    r.Prevailing = !objSym.isUndefined() && sym->file == &f;244 245    // We ask LTO to preserve following global symbols:246    // 1) All symbols when doing relocatable link, so that them can be used247    //    for doing final link.248    // 2) Symbols that are used in regular objects.249    // 3) C named sections if we have corresponding __start_/__stop_ symbol.250    // 4) Symbols that are defined in bitcode files and used for dynamic251    //    linking.252    // 5) Symbols that will be referenced after linker wrapping is performed.253    r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||254                            sym->referencedAfterWrap ||255                            (r.Prevailing && sym->isExported) ||256                            usedStartStop.count(objSym.getSectionName());257    // Identify symbols exported dynamically, and that therefore could be258    // referenced by a shared library not visible to the linker.259    r.ExportDynamic = sym->computeBinding(ctx) != STB_LOCAL &&260                      (ctx.arg.exportDynamic || sym->isExported);261    const auto *dr = dyn_cast<Defined>(sym);262    r.FinalDefinitionInLinkageUnit =263        (isExec || sym->visibility() != STV_DEFAULT) && dr &&264        // Skip absolute symbols from ELF objects, otherwise PC-rel relocations265        // will be generated by for them, triggering linker errors.266        // Symbol section is always null for bitcode symbols, hence the check267        // for isElf(). Skip linker script defined symbols as well: they have268        // no File defined.269        !(dr->section == nullptr &&270          (sym->file->isInternal() || sym->file->isElf()));271 272    if (r.Prevailing)273      Undefined(ctx.internalFile, StringRef(), STB_GLOBAL, STV_DEFAULT,274                sym->type)275          .overwrite(*sym);276 277    // We tell LTO to not apply interprocedural optimization for wrapped278    // (with --wrap) symbols because otherwise LTO would inline them while279    // their values are still not final.280    r.LinkerRedefined = sym->scriptDefined;281  }282  checkError(ctx.e, ltoObj->add(std::move(f.obj), resols));283}284 285// If LazyObjFile has not been added to link, emit empty index files.286// This is needed because this is what GNU gold plugin does and we have a287// distributed build system that depends on that behavior.288static void thinLTOCreateEmptyIndexFiles(Ctx &ctx) {289  DenseSet<StringRef> linkedBitCodeFiles;290  for (BitcodeFile *f : ctx.bitcodeFiles)291    linkedBitCodeFiles.insert(f->getName());292 293  for (BitcodeFile *f : ctx.lazyBitcodeFiles) {294    if (!f->lazy)295      continue;296    if (linkedBitCodeFiles.contains(f->getName()))297      continue;298    std::string path =299        replaceThinLTOSuffix(ctx, getThinLTOOutputFile(ctx, f->obj->getName()));300    std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");301    if (!os)302      continue;303 304    ModuleSummaryIndex m(/*HaveGVs*/ false);305    m.setSkipModuleByDistributedBackend();306    writeIndexToFile(m, *os);307    if (ctx.arg.thinLTOEmitImportsFiles)308      openFile(path + ".imports");309  }310}311 312// Merge all the bitcode files we have seen, codegen the result313// and return the resulting ObjectFile(s).314SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {315  unsigned maxTasks = ltoObj->getMaxTasks();316  buf.resize(maxTasks);317  files.resize(maxTasks);318  filenames.resize(maxTasks);319 320  // The --thinlto-cache-dir option specifies the path to a directory in which321  // to cache native object files for ThinLTO incremental builds. If a path was322  // specified, configure LTO to use it as the cache directory.323  FileCache cache;324  if (!ctx.arg.thinLTOCacheDir.empty())325    cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir,326                             [&](size_t task, const Twine &moduleName,327                                 std::unique_ptr<MemoryBuffer> mb) {328                               files[task] = std::move(mb);329                               filenames[task] = moduleName.str();330                             }));331 332  if (!ctx.bitcodeFiles.empty())333    checkError(ctx.e, ltoObj->run(334                          [&](size_t task, const Twine &moduleName) {335                            buf[task].first = moduleName.str();336                            return std::make_unique<CachedFileStream>(337                                std::make_unique<raw_svector_ostream>(338                                    buf[task].second));339                          },340                          cache));341 342  // Emit empty index files for non-indexed files but not in single-module mode.343  if (ctx.arg.thinLTOModulesToCompile.empty()) {344    for (StringRef s : thinIndices) {345      std::string path = getThinLTOOutputFile(ctx, s);346      openFile(path + ".thinlto.bc");347      if (ctx.arg.thinLTOEmitImportsFiles)348        openFile(path + ".imports");349    }350  }351 352  if (ctx.arg.thinLTOEmitIndexFiles)353    thinLTOCreateEmptyIndexFiles(ctx);354 355  if (ctx.arg.thinLTOIndexOnly) {356    if (!ctx.arg.ltoObjPath.empty())357      saveBuffer(buf[0].second, ctx.arg.ltoObjPath);358 359    // ThinLTO with index only option is required to generate only the index360    // files. After that, we exit from linker and ThinLTO backend runs in a361    // distributed environment.362    if (indexFile)363      indexFile->close();364    return {};365  }366 367  if (!ctx.arg.thinLTOCacheDir.empty())368    pruneCache(ctx.arg.thinLTOCacheDir, ctx.arg.thinLTOCachePolicy, files);369 370  if (!ctx.arg.ltoObjPath.empty()) {371    saveBuffer(buf[0].second, ctx.arg.ltoObjPath);372    for (unsigned i = 1; i != maxTasks; ++i)373      saveBuffer(buf[i].second, ctx.arg.ltoObjPath + Twine(i));374  }375 376  bool savePrelink = ctx.arg.saveTempsArgs.contains("prelink");377  SmallVector<std::unique_ptr<InputFile>, 0> ret;378  const char *ext = ctx.arg.ltoEmitAsm ? ".s" : ".o";379  for (unsigned i = 0; i != maxTasks; ++i) {380    StringRef bitcodeFilePath;381    StringRef objBuf;382    if (files[i]) {383      // When files[i] is not null, we get the native relocatable file from the384      // cache. filenames[i] contains the original BitcodeFile's identifier.385      objBuf = files[i]->getBuffer();386      bitcodeFilePath = filenames[i];387    } else {388      // Get the native relocatable file after in-process LTO compilation.389      objBuf = buf[i].second;390      bitcodeFilePath = buf[i].first;391    }392    if (objBuf.empty())393      continue;394 395    // If the input bitcode file is path/to/x.o and -o specifies a.out, the396    // corresponding native relocatable file path will look like:397    // path/to/a.out.lto.x.o.398    StringRef ltoObjName;399    if (bitcodeFilePath == "ld-temp.o") {400      ltoObjName =401          ctx.saver.save(Twine(ctx.arg.outputFile) + ".lto" +402                         (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ext);403    } else {404      StringRef directory = sys::path::parent_path(bitcodeFilePath);405      // For an archive member, which has an identifier like "d/a.a(coll.o at406      // 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use407      // the stem (d/a.o => a).408      StringRef baseName = bitcodeFilePath.ends_with(")")409                               ? sys::path::filename(bitcodeFilePath)410                               : sys::path::stem(bitcodeFilePath);411      StringRef outputFileBaseName = sys::path::filename(ctx.arg.outputFile);412      SmallString<256> path;413      sys::path::append(path, directory,414                        outputFileBaseName + ".lto." + baseName + ext);415      sys::path::remove_dots(path, true);416      ltoObjName = ctx.saver.save(path.str());417    }418    if (savePrelink || ctx.arg.ltoEmitAsm)419      saveBuffer(buf[i].second, ltoObjName);420    if (!ctx.arg.ltoEmitAsm)421      ret.push_back(createObjFile(ctx, MemoryBufferRef(objBuf, ltoObjName)));422  }423  return ret;424}425