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