brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.5 KiB · 668cdf2 Raw
292 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 "Symbols.h"13#include "lld/Common/CommonLinkerContext.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/Bitcode/BitcodeWriter.h"21#include "llvm/IR/DiagnosticPrinter.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 "llvm/Support/raw_ostream.h"29#include <cstddef>30#include <memory>31#include <string>32#include <vector>33 34using namespace llvm;35using namespace lld::wasm;36using namespace lld;37 38static std::string getThinLTOOutputFile(StringRef modulePath) {39  return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld,40                                   ctx.arg.thinLTOPrefixReplaceNew);41}42 43static lto::Config createConfig() {44  lto::Config c;45  c.Options = initTargetOptionsFromCodeGenFlags();46 47  // Always emit a section per function/data with LTO.48  c.Options.FunctionSections = true;49  c.Options.DataSections = true;50 51  c.DisableVerify = ctx.arg.disableVerify;52  c.DiagHandler = diagnosticHandler;53  c.OptLevel = ctx.arg.ltoo;54  c.CPU = getCPUStr();55  c.MAttrs = getMAttrs();56  c.CGOptLevel = ctx.arg.ltoCgo;57  c.DebugPassManager = ctx.arg.ltoDebugPassManager;58  c.AlwaysEmitRegularLTOObj = !ctx.arg.ltoObjPath.empty();59 60  if (auto relocModel = getRelocModelFromCMModel())61    c.RelocModel = *relocModel;62  else if (ctx.arg.relocatable)63    c.RelocModel = std::nullopt;64  else if (ctx.isPic)65    c.RelocModel = Reloc::PIC_;66  else if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)67    // With ImportDynamic we also need to use the PIC relocation model so that68    // external symbols are references via the GOT.69    // TODO(sbc): This should probably be Reloc::DynamicNoPIC, but the backend70    // doesn't currently support that.71    c.RelocModel = Reloc::PIC_;72  else73    c.RelocModel = Reloc::Static;74 75  if (ctx.arg.saveTemps)76    checkError(c.addSaveTemps(ctx.arg.outputFile.str() + ".",77                              /*UseInputModulePath*/ true));78  return c;79}80 81namespace lld::wasm {82 83BitcodeCompiler::BitcodeCompiler() {84  // Initialize indexFile.85  if (!ctx.arg.thinLTOIndexOnlyArg.empty())86    indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg);87 88  // Initialize ltoObj.89  lto::ThinBackend backend;90  auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); };91  if (ctx.arg.thinLTOIndexOnly) {92    backend = lto::createWriteIndexesThinBackend(93        llvm::hardware_concurrency(ctx.arg.thinLTOJobs),94        std::string(ctx.arg.thinLTOPrefixReplaceOld),95        std::string(ctx.arg.thinLTOPrefixReplaceNew),96        std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),97        ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);98  } else {99    backend = lto::createInProcessThinBackend(100        llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs),101        onIndexWrite, ctx.arg.thinLTOEmitIndexFiles,102        ctx.arg.thinLTOEmitImportsFiles);103  }104  ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,105                                      ctx.arg.ltoPartitions);106}107 108BitcodeCompiler::~BitcodeCompiler() = default;109 110static void undefine(Symbol *s) {111  if (auto f = dyn_cast<DefinedFunction>(s))112    // If the signature is null, there were no calls from non-bitcode objects.113    replaceSymbol<UndefinedFunction>(f, f->getName(), std::nullopt,114                                     std::nullopt, 0, f->getFile(),115                                     f->signature, f->signature != nullptr);116  else if (isa<DefinedData>(s))117    replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile());118  else119    llvm_unreachable("unexpected symbol kind");120}121 122void BitcodeCompiler::add(BitcodeFile &f) {123  lto::InputFile &obj = *f.obj;124  unsigned symNum = 0;125  ArrayRef<Symbol *> syms = f.getSymbols();126  std::vector<lto::SymbolResolution> resols(syms.size());127 128  if (ctx.arg.thinLTOEmitIndexFiles) {129    thinIndices.insert(obj.getName());130  }131 132  // Provide a resolution to the LTO API for each symbol.133  for (const lto::InputFile::Symbol &objSym : obj.symbols()) {134    Symbol *sym = syms[symNum];135    lto::SymbolResolution &r = resols[symNum];136    ++symNum;137 138    // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile139    // reports two symbols for module ASM defined. Without this check, lld140    // flags an undefined in IR with a definition in ASM as prevailing.141    // Once IRObjectFile is fixed to report only one symbol this hack can142    // be removed.143    r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;144    r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||145                            sym->isNoStrip() ||146                            (r.Prevailing && sym->isExported());147    if (r.Prevailing)148      undefine(sym);149 150    // We tell LTO to not apply interprocedural optimization for wrapped151    // (with --wrap) symbols because otherwise LTO would inline them while152    // their values are still not final.153    r.LinkerRedefined = !sym->canInline;154  }155  checkError(ltoObj->add(std::move(f.obj), resols));156}157 158// If LazyObjFile has not been added to link, emit empty index files.159// This is needed because this is what GNU gold plugin does and we have a160// distributed build system that depends on that behavior.161static void thinLTOCreateEmptyIndexFiles() {162  DenseSet<StringRef> linkedBitCodeFiles;163  for (BitcodeFile *f : ctx.bitcodeFiles)164    linkedBitCodeFiles.insert(f->getName());165 166  for (BitcodeFile *f : ctx.lazyBitcodeFiles) {167    if (!f->lazy)168      continue;169    if (linkedBitCodeFiles.contains(f->getName()))170      continue;171    std::string path =172        replaceThinLTOSuffix(getThinLTOOutputFile(f->obj->getName()));173    std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");174    if (!os)175      continue;176 177    ModuleSummaryIndex m(/*HaveGVs*/ false);178    m.setSkipModuleByDistributedBackend();179    writeIndexToFile(m, *os);180    if (ctx.arg.thinLTOEmitImportsFiles)181      openFile(path + ".imports");182  }183}184 185// Merge all the bitcode files we have seen, codegen the result186// and return the resulting objects.187SmallVector<InputFile *, 0> BitcodeCompiler::compile() {188  unsigned maxTasks = ltoObj->getMaxTasks();189  buf.resize(maxTasks);190  files.resize(maxTasks);191  filenames.resize(maxTasks);192 193  // The --thinlto-cache-dir option specifies the path to a directory in which194  // to cache native object files for ThinLTO incremental builds. If a path was195  // specified, configure LTO to use it as the cache directory.196  FileCache cache;197  if (!ctx.arg.thinLTOCacheDir.empty())198    cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir,199                             [&](size_t task, const Twine &moduleName,200                                 std::unique_ptr<MemoryBuffer> mb) {201                               files[task] = std::move(mb);202                             }));203 204  checkError(ltoObj->run(205      [&](size_t task, const Twine &moduleName) {206        buf[task].first = moduleName.str();207        return std::make_unique<CachedFileStream>(208            std::make_unique<raw_svector_ostream>(buf[task].second));209      },210      cache));211 212  // Emit empty index files for non-indexed files but not in single-module mode.213  for (StringRef s : thinIndices) {214    std::string path(s);215    openFile(path + ".thinlto.bc");216    if (ctx.arg.thinLTOEmitImportsFiles)217      openFile(path + ".imports");218  }219 220  if (ctx.arg.thinLTOEmitIndexFiles)221    thinLTOCreateEmptyIndexFiles();222 223  if (ctx.arg.thinLTOIndexOnly) {224    if (!ctx.arg.ltoObjPath.empty())225      saveBuffer(buf[0].second, ctx.arg.ltoObjPath);226 227    // ThinLTO with index only option is required to generate only the index228    // files. After that, we exit from linker and ThinLTO backend runs in a229    // distributed environment.230    if (indexFile)231      indexFile->close();232    return {};233  }234 235  if (!ctx.arg.thinLTOCacheDir.empty())236    pruneCache(ctx.arg.thinLTOCacheDir, ctx.arg.thinLTOCachePolicy, files);237 238  SmallVector<InputFile *, 0> ret;239  for (unsigned i = 0; i != maxTasks; ++i) {240    StringRef objBuf = buf[i].second;241    StringRef bitcodeFilePath = buf[i].first;242    if (files[i]) {243      // When files[i] is not null, we get the native relocatable file from the244      // cache. filenames[i] contains the original BitcodeFile's identifier.245      objBuf = files[i]->getBuffer();246      bitcodeFilePath = filenames[i];247    } else {248      objBuf = buf[i].second;249      bitcodeFilePath = buf[i].first;250    }251    if (objBuf.empty())252      continue;253 254    // If the input bitcode file is path/to/x.o and -o specifies a.out, the255    // corresponding native relocatable file path will look like:256    // path/to/a.out.lto.x.o.257    StringRef ltoObjName;258    if (bitcodeFilePath == "ld-temp.o") {259      ltoObjName =260          saver().save(Twine(ctx.arg.outputFile) + ".lto" +261                       (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o");262    } else {263      StringRef directory = sys::path::parent_path(bitcodeFilePath);264      // For an archive member, which has an identifier like "d/a.a(coll.o at265      // 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use266      // the stem (d/a.o => a).267      StringRef baseName = bitcodeFilePath.ends_with(")")268                               ? sys::path::filename(bitcodeFilePath)269                               : sys::path::stem(bitcodeFilePath);270      StringRef outputFileBaseName = sys::path::filename(ctx.arg.outputFile);271      SmallString<256> path;272      sys::path::append(path, directory,273                        outputFileBaseName + ".lto." + baseName + ".o");274      sys::path::remove_dots(path, true);275      ltoObjName = saver().save(path.str());276    }277    if (ctx.arg.saveTemps)278      saveBuffer(objBuf, ltoObjName);279    ret.emplace_back(createObjectFile(MemoryBufferRef(objBuf, ltoObjName)));280  }281 282  if (!ctx.arg.ltoObjPath.empty()) {283    saveBuffer(buf[0].second, ctx.arg.ltoObjPath);284    for (unsigned i = 1; i != maxTasks; ++i)285      saveBuffer(buf[i].second, ctx.arg.ltoObjPath + Twine(i));286  }287 288  return ret;289}290 291} // namespace lld::wasm292