Path: blob/main/contrib/llvm-project/lld/ELF/LTO.cpp
34878 views
//===- LTO.cpp ------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "LTO.h"9#include "Config.h"10#include "InputFiles.h"11#include "SymbolTable.h"12#include "Symbols.h"13#include "lld/Common/Args.h"14#include "lld/Common/CommonLinkerContext.h"15#include "lld/Common/ErrorHandler.h"16#include "lld/Common/Filesystem.h"17#include "lld/Common/Strings.h"18#include "lld/Common/TargetOptionsCommandFlags.h"19#include "llvm/ADT/SmallString.h"20#include "llvm/ADT/StringRef.h"21#include "llvm/ADT/Twine.h"22#include "llvm/BinaryFormat/ELF.h"23#include "llvm/Bitcode/BitcodeWriter.h"24#include "llvm/LTO/Config.h"25#include "llvm/LTO/LTO.h"26#include "llvm/Support/Caching.h"27#include "llvm/Support/CodeGen.h"28#include "llvm/Support/Error.h"29#include "llvm/Support/FileSystem.h"30#include "llvm/Support/MemoryBuffer.h"31#include "llvm/Support/Path.h"32#include <algorithm>33#include <cstddef>34#include <memory>35#include <string>36#include <system_error>37#include <vector>3839using namespace llvm;40using namespace llvm::object;41using namespace llvm::ELF;42using namespace lld;43using namespace lld::elf;4445static std::string getThinLTOOutputFile(StringRef modulePath) {46return lto::getThinLTOOutputFile(modulePath, config->thinLTOPrefixReplaceOld,47config->thinLTOPrefixReplaceNew);48}4950static lto::Config createConfig() {51lto::Config c;5253// LLD supports the new relocations and address-significance tables.54c.Options = initTargetOptionsFromCodeGenFlags();55c.Options.EmitAddrsig = true;56for (StringRef C : config->mllvmOpts)57c.MllvmArgs.emplace_back(C.str());5859// Always emit a section per function/datum with LTO.60c.Options.FunctionSections = true;61c.Options.DataSections = true;6263c.Options.BBAddrMap = config->ltoBBAddrMap;6465// Check if basic block sections must be used.66// Allowed values for --lto-basic-block-sections are "all", "labels",67// "<file name specifying basic block ids>", or none. This is the equivalent68// of -fbasic-block-sections= flag in clang.69if (!config->ltoBasicBlockSections.empty()) {70if (config->ltoBasicBlockSections == "all") {71c.Options.BBSections = BasicBlockSection::All;72} else if (config->ltoBasicBlockSections == "labels") {73c.Options.BBSections = BasicBlockSection::Labels;74} else if (config->ltoBasicBlockSections == "none") {75c.Options.BBSections = BasicBlockSection::None;76} else {77ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =78MemoryBuffer::getFile(config->ltoBasicBlockSections.str());79if (!MBOrErr) {80error("cannot open " + config->ltoBasicBlockSections + ":" +81MBOrErr.getError().message());82} else {83c.Options.BBSectionsFuncListBuf = std::move(*MBOrErr);84}85c.Options.BBSections = BasicBlockSection::List;86}87}8889c.Options.UniqueBasicBlockSectionNames =90config->ltoUniqueBasicBlockSectionNames;9192if (auto relocModel = getRelocModelFromCMModel())93c.RelocModel = *relocModel;94else if (config->relocatable)95c.RelocModel = std::nullopt;96else if (config->isPic)97c.RelocModel = Reloc::PIC_;98else99c.RelocModel = Reloc::Static;100101c.CodeModel = getCodeModelFromCMModel();102c.DisableVerify = config->disableVerify;103c.DiagHandler = diagnosticHandler;104c.OptLevel = config->ltoo;105c.CPU = getCPUStr();106c.MAttrs = getMAttrs();107c.CGOptLevel = config->ltoCgo;108109c.PTO.LoopVectorization = c.OptLevel > 1;110c.PTO.SLPVectorization = c.OptLevel > 1;111112// Set up a custom pipeline if we've been asked to.113c.OptPipeline = std::string(config->ltoNewPmPasses);114c.AAPipeline = std::string(config->ltoAAPipeline);115116// Set up optimization remarks if we've been asked to.117c.RemarksFilename = std::string(config->optRemarksFilename);118c.RemarksPasses = std::string(config->optRemarksPasses);119c.RemarksWithHotness = config->optRemarksWithHotness;120c.RemarksHotnessThreshold = config->optRemarksHotnessThreshold;121c.RemarksFormat = std::string(config->optRemarksFormat);122123// Set up output file to emit statistics.124c.StatsFile = std::string(config->optStatsFilename);125126c.SampleProfile = std::string(config->ltoSampleProfile);127for (StringRef pluginFn : config->passPlugins)128c.PassPlugins.push_back(std::string(pluginFn));129c.DebugPassManager = config->ltoDebugPassManager;130c.DwoDir = std::string(config->dwoDir);131132c.HasWholeProgramVisibility = config->ltoWholeProgramVisibility;133c.ValidateAllVtablesHaveTypeInfos =134config->ltoValidateAllVtablesHaveTypeInfos;135c.AllVtablesHaveTypeInfos = ctx.ltoAllVtablesHaveTypeInfos;136c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();137138for (const llvm::StringRef &name : config->thinLTOModulesToCompile)139c.ThinLTOModulesToCompile.emplace_back(name);140141c.TimeTraceEnabled = config->timeTraceEnabled;142c.TimeTraceGranularity = config->timeTraceGranularity;143144c.CSIRProfile = std::string(config->ltoCSProfileFile);145c.RunCSIRInstr = config->ltoCSProfileGenerate;146c.PGOWarnMismatch = config->ltoPGOWarnMismatch;147148if (config->emitLLVM) {149c.PreCodeGenModuleHook = [](size_t task, const Module &m) {150if (std::unique_ptr<raw_fd_ostream> os =151openLTOOutputFile(config->outputFile))152WriteBitcodeToFile(m, *os, false);153return false;154};155}156157if (config->ltoEmitAsm) {158c.CGFileType = CodeGenFileType::AssemblyFile;159c.Options.MCOptions.AsmVerbose = true;160}161162if (!config->saveTempsArgs.empty())163checkError(c.addSaveTemps(config->outputFile.str() + ".",164/*UseInputModulePath*/ true,165config->saveTempsArgs));166return c;167}168169BitcodeCompiler::BitcodeCompiler() {170// Initialize indexFile.171if (!config->thinLTOIndexOnlyArg.empty())172indexFile = openFile(config->thinLTOIndexOnlyArg);173174// Initialize ltoObj.175lto::ThinBackend backend;176auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); };177if (config->thinLTOIndexOnly) {178backend = lto::createWriteIndexesThinBackend(179std::string(config->thinLTOPrefixReplaceOld),180std::string(config->thinLTOPrefixReplaceNew),181std::string(config->thinLTOPrefixReplaceNativeObject),182config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);183} else {184backend = lto::createInProcessThinBackend(185llvm::heavyweight_hardware_concurrency(config->thinLTOJobs),186onIndexWrite, config->thinLTOEmitIndexFiles,187config->thinLTOEmitImportsFiles);188}189190constexpr llvm::lto::LTO::LTOKind ltoModes[3] =191{llvm::lto::LTO::LTOKind::LTOK_UnifiedThin,192llvm::lto::LTO::LTOKind::LTOK_UnifiedRegular,193llvm::lto::LTO::LTOKind::LTOK_Default};194ltoObj = std::make_unique<lto::LTO>(195createConfig(), backend, config->ltoPartitions,196ltoModes[config->ltoKind]);197198// Initialize usedStartStop.199if (ctx.bitcodeFiles.empty())200return;201for (Symbol *sym : symtab.getSymbols()) {202if (sym->isPlaceholder())203continue;204StringRef s = sym->getName();205for (StringRef prefix : {"__start_", "__stop_"})206if (s.starts_with(prefix))207usedStartStop.insert(s.substr(prefix.size()));208}209}210211BitcodeCompiler::~BitcodeCompiler() = default;212213void BitcodeCompiler::add(BitcodeFile &f) {214lto::InputFile &obj = *f.obj;215bool isExec = !config->shared && !config->relocatable;216217if (config->thinLTOEmitIndexFiles)218thinIndices.insert(obj.getName());219220ArrayRef<Symbol *> syms = f.getSymbols();221ArrayRef<lto::InputFile::Symbol> objSyms = obj.symbols();222std::vector<lto::SymbolResolution> resols(syms.size());223224// Provide a resolution to the LTO API for each symbol.225for (size_t i = 0, e = syms.size(); i != e; ++i) {226Symbol *sym = syms[i];227const lto::InputFile::Symbol &objSym = objSyms[i];228lto::SymbolResolution &r = resols[i];229230// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile231// reports two symbols for module ASM defined. Without this check, lld232// flags an undefined in IR with a definition in ASM as prevailing.233// Once IRObjectFile is fixed to report only one symbol this hack can234// be removed.235r.Prevailing = !objSym.isUndefined() && sym->file == &f;236237// We ask LTO to preserve following global symbols:238// 1) All symbols when doing relocatable link, so that them can be used239// for doing final link.240// 2) Symbols that are used in regular objects.241// 3) C named sections if we have corresponding __start_/__stop_ symbol.242// 4) Symbols that are defined in bitcode files and used for dynamic243// linking.244// 5) Symbols that will be referenced after linker wrapping is performed.245r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||246sym->referencedAfterWrap ||247(r.Prevailing && sym->includeInDynsym()) ||248usedStartStop.count(objSym.getSectionName());249// Identify symbols exported dynamically, and that therefore could be250// referenced by a shared library not visible to the linker.251r.ExportDynamic =252sym->computeBinding() != STB_LOCAL &&253(config->exportDynamic || sym->exportDynamic || sym->inDynamicList);254const auto *dr = dyn_cast<Defined>(sym);255r.FinalDefinitionInLinkageUnit =256(isExec || sym->visibility() != STV_DEFAULT) && dr &&257// Skip absolute symbols from ELF objects, otherwise PC-rel relocations258// will be generated by for them, triggering linker errors.259// Symbol section is always null for bitcode symbols, hence the check260// for isElf(). Skip linker script defined symbols as well: they have261// no File defined.262!(dr->section == nullptr &&263(sym->file->isInternal() || sym->file->isElf()));264265if (r.Prevailing)266Undefined(ctx.internalFile, StringRef(), STB_GLOBAL, STV_DEFAULT,267sym->type)268.overwrite(*sym);269270// We tell LTO to not apply interprocedural optimization for wrapped271// (with --wrap) symbols because otherwise LTO would inline them while272// their values are still not final.273r.LinkerRedefined = sym->scriptDefined;274}275checkError(ltoObj->add(std::move(f.obj), resols));276}277278// If LazyObjFile has not been added to link, emit empty index files.279// This is needed because this is what GNU gold plugin does and we have a280// distributed build system that depends on that behavior.281static void thinLTOCreateEmptyIndexFiles() {282DenseSet<StringRef> linkedBitCodeFiles;283for (BitcodeFile *f : ctx.bitcodeFiles)284linkedBitCodeFiles.insert(f->getName());285286for (BitcodeFile *f : ctx.lazyBitcodeFiles) {287if (!f->lazy)288continue;289if (linkedBitCodeFiles.contains(f->getName()))290continue;291std::string path =292replaceThinLTOSuffix(getThinLTOOutputFile(f->obj->getName()));293std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");294if (!os)295continue;296297ModuleSummaryIndex m(/*HaveGVs*/ false);298m.setSkipModuleByDistributedBackend();299writeIndexToFile(m, *os);300if (config->thinLTOEmitImportsFiles)301openFile(path + ".imports");302}303}304305// Merge all the bitcode files we have seen, codegen the result306// and return the resulting ObjectFile(s).307std::vector<InputFile *> BitcodeCompiler::compile() {308unsigned maxTasks = ltoObj->getMaxTasks();309buf.resize(maxTasks);310files.resize(maxTasks);311filenames.resize(maxTasks);312313// The --thinlto-cache-dir option specifies the path to a directory in which314// to cache native object files for ThinLTO incremental builds. If a path was315// specified, configure LTO to use it as the cache directory.316FileCache cache;317if (!config->thinLTOCacheDir.empty())318cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,319[&](size_t task, const Twine &moduleName,320std::unique_ptr<MemoryBuffer> mb) {321files[task] = std::move(mb);322filenames[task] = moduleName.str();323}));324325if (!ctx.bitcodeFiles.empty())326checkError(ltoObj->run(327[&](size_t task, const Twine &moduleName) {328buf[task].first = moduleName.str();329return std::make_unique<CachedFileStream>(330std::make_unique<raw_svector_ostream>(buf[task].second));331},332cache));333334// Emit empty index files for non-indexed files but not in single-module mode.335if (config->thinLTOModulesToCompile.empty()) {336for (StringRef s : thinIndices) {337std::string path = getThinLTOOutputFile(s);338openFile(path + ".thinlto.bc");339if (config->thinLTOEmitImportsFiles)340openFile(path + ".imports");341}342}343344if (config->thinLTOEmitIndexFiles)345thinLTOCreateEmptyIndexFiles();346347if (config->thinLTOIndexOnly) {348if (!config->ltoObjPath.empty())349saveBuffer(buf[0].second, config->ltoObjPath);350351// ThinLTO with index only option is required to generate only the index352// files. After that, we exit from linker and ThinLTO backend runs in a353// distributed environment.354if (indexFile)355indexFile->close();356return {};357}358359if (!config->thinLTOCacheDir.empty())360pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files);361362if (!config->ltoObjPath.empty()) {363saveBuffer(buf[0].second, config->ltoObjPath);364for (unsigned i = 1; i != maxTasks; ++i)365saveBuffer(buf[i].second, config->ltoObjPath + Twine(i));366}367368bool savePrelink = config->saveTempsArgs.contains("prelink");369std::vector<InputFile *> ret;370const char *ext = config->ltoEmitAsm ? ".s" : ".o";371for (unsigned i = 0; i != maxTasks; ++i) {372StringRef bitcodeFilePath;373StringRef objBuf;374if (files[i]) {375// When files[i] is not null, we get the native relocatable file from the376// cache. filenames[i] contains the original BitcodeFile's identifier.377objBuf = files[i]->getBuffer();378bitcodeFilePath = filenames[i];379} else {380// Get the native relocatable file after in-process LTO compilation.381objBuf = buf[i].second;382bitcodeFilePath = buf[i].first;383}384if (objBuf.empty())385continue;386387// If the input bitcode file is path/to/x.o and -o specifies a.out, the388// corresponding native relocatable file path will look like:389// path/to/a.out.lto.x.o.390StringRef ltoObjName;391if (bitcodeFilePath == "ld-temp.o") {392ltoObjName =393saver().save(Twine(config->outputFile) + ".lto" +394(i == 0 ? Twine("") : Twine('.') + Twine(i)) + ext);395} else {396StringRef directory = sys::path::parent_path(bitcodeFilePath);397// For an archive member, which has an identifier like "d/a.a(coll.o at398// 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use399// the stem (d/a.o => a).400StringRef baseName = bitcodeFilePath.ends_with(")")401? sys::path::filename(bitcodeFilePath)402: sys::path::stem(bitcodeFilePath);403StringRef outputFileBaseName = sys::path::filename(config->outputFile);404SmallString<256> path;405sys::path::append(path, directory,406outputFileBaseName + ".lto." + baseName + ext);407sys::path::remove_dots(path, true);408ltoObjName = saver().save(path.str());409}410if (savePrelink || config->ltoEmitAsm)411saveBuffer(buf[i].second, ltoObjName);412if (!config->ltoEmitAsm)413ret.push_back(createObjFile(MemoryBufferRef(objBuf, ltoObjName)));414}415return ret;416}417418419