xref: /openbsd-src/gnu/llvm/lld/wasm/LTO.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- LTO.cpp ------------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "LTO.h"
10ece8a530Spatrick #include "Config.h"
11ece8a530Spatrick #include "InputFiles.h"
12ece8a530Spatrick #include "Symbols.h"
13ece8a530Spatrick #include "lld/Common/Args.h"
14ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
15ece8a530Spatrick #include "lld/Common/Strings.h"
16ece8a530Spatrick #include "lld/Common/TargetOptionsCommandFlags.h"
17ece8a530Spatrick #include "llvm/ADT/STLExtras.h"
18ece8a530Spatrick #include "llvm/ADT/SmallString.h"
19ece8a530Spatrick #include "llvm/ADT/StringRef.h"
20ece8a530Spatrick #include "llvm/ADT/Twine.h"
21ece8a530Spatrick #include "llvm/IR/DiagnosticPrinter.h"
22ece8a530Spatrick #include "llvm/LTO/Config.h"
23ece8a530Spatrick #include "llvm/LTO/LTO.h"
24ece8a530Spatrick #include "llvm/Object/SymbolicFile.h"
25*dfe94b16Srobert #include "llvm/Support/Caching.h"
26ece8a530Spatrick #include "llvm/Support/CodeGen.h"
27ece8a530Spatrick #include "llvm/Support/Error.h"
28ece8a530Spatrick #include "llvm/Support/FileSystem.h"
29ece8a530Spatrick #include "llvm/Support/MemoryBuffer.h"
30ece8a530Spatrick #include "llvm/Support/raw_ostream.h"
31ece8a530Spatrick #include <algorithm>
32ece8a530Spatrick #include <cstddef>
33ece8a530Spatrick #include <memory>
34ece8a530Spatrick #include <string>
35ece8a530Spatrick #include <system_error>
36ece8a530Spatrick #include <vector>
37ece8a530Spatrick 
38ece8a530Spatrick using namespace llvm;
39ece8a530Spatrick 
40ece8a530Spatrick namespace lld {
41ece8a530Spatrick namespace wasm {
createLTO()42ece8a530Spatrick static std::unique_ptr<lto::LTO> createLTO() {
43ece8a530Spatrick   lto::Config c;
44ece8a530Spatrick   c.Options = initTargetOptionsFromCodeGenFlags();
45ece8a530Spatrick 
46ece8a530Spatrick   // Always emit a section per function/data with LTO.
47ece8a530Spatrick   c.Options.FunctionSections = true;
48ece8a530Spatrick   c.Options.DataSections = true;
49ece8a530Spatrick 
50ece8a530Spatrick   c.DisableVerify = config->disableVerify;
51ece8a530Spatrick   c.DiagHandler = diagnosticHandler;
52ece8a530Spatrick   c.OptLevel = config->ltoo;
53ece8a530Spatrick   c.MAttrs = getMAttrs();
54ece8a530Spatrick   c.CGOptLevel = args::getCGOptLevel(config->ltoo);
551cf9926bSpatrick   c.DebugPassManager = config->ltoDebugPassManager;
56ece8a530Spatrick 
57ece8a530Spatrick   if (config->relocatable)
58*dfe94b16Srobert     c.RelocModel = std::nullopt;
59ece8a530Spatrick   else if (config->isPic)
60ece8a530Spatrick     c.RelocModel = Reloc::PIC_;
61ece8a530Spatrick   else
62ece8a530Spatrick     c.RelocModel = Reloc::Static;
63ece8a530Spatrick 
64ece8a530Spatrick   if (config->saveTemps)
65ece8a530Spatrick     checkError(c.addSaveTemps(config->outputFile.str() + ".",
66ece8a530Spatrick                               /*UseInputModulePath*/ true));
67bb684c34Spatrick   lto::ThinBackend backend = lto::createInProcessThinBackend(
68bb684c34Spatrick       llvm::heavyweight_hardware_concurrency(config->thinLTOJobs));
69ece8a530Spatrick   return std::make_unique<lto::LTO>(std::move(c), backend,
70ece8a530Spatrick                                      config->ltoPartitions);
71ece8a530Spatrick }
72ece8a530Spatrick 
BitcodeCompiler()73ece8a530Spatrick BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {}
74ece8a530Spatrick 
75ece8a530Spatrick BitcodeCompiler::~BitcodeCompiler() = default;
76ece8a530Spatrick 
undefine(Symbol * s)77ece8a530Spatrick static void undefine(Symbol *s) {
78ece8a530Spatrick   if (auto f = dyn_cast<DefinedFunction>(s))
79*dfe94b16Srobert     replaceSymbol<UndefinedFunction>(f, f->getName(), std::nullopt,
80*dfe94b16Srobert                                      std::nullopt, 0, f->getFile(),
81*dfe94b16Srobert                                      f->signature);
82ece8a530Spatrick   else if (isa<DefinedData>(s))
83ece8a530Spatrick     replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile());
84ece8a530Spatrick   else
85ece8a530Spatrick     llvm_unreachable("unexpected symbol kind");
86ece8a530Spatrick }
87ece8a530Spatrick 
add(BitcodeFile & f)88ece8a530Spatrick void BitcodeCompiler::add(BitcodeFile &f) {
89ece8a530Spatrick   lto::InputFile &obj = *f.obj;
90ece8a530Spatrick   unsigned symNum = 0;
91ece8a530Spatrick   ArrayRef<Symbol *> syms = f.getSymbols();
92ece8a530Spatrick   std::vector<lto::SymbolResolution> resols(syms.size());
93ece8a530Spatrick 
94ece8a530Spatrick   // Provide a resolution to the LTO API for each symbol.
95ece8a530Spatrick   for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
96ece8a530Spatrick     Symbol *sym = syms[symNum];
97ece8a530Spatrick     lto::SymbolResolution &r = resols[symNum];
98ece8a530Spatrick     ++symNum;
99ece8a530Spatrick 
100ece8a530Spatrick     // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
101ece8a530Spatrick     // reports two symbols for module ASM defined. Without this check, lld
102ece8a530Spatrick     // flags an undefined in IR with a definition in ASM as prevailing.
103ece8a530Spatrick     // Once IRObjectFile is fixed to report only one symbol this hack can
104ece8a530Spatrick     // be removed.
105ece8a530Spatrick     r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
106ece8a530Spatrick     r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||
107ece8a530Spatrick                             sym->isNoStrip() ||
108ece8a530Spatrick                             (r.Prevailing && sym->isExported());
109ece8a530Spatrick     if (r.Prevailing)
110ece8a530Spatrick       undefine(sym);
111ece8a530Spatrick 
112ece8a530Spatrick     // We tell LTO to not apply interprocedural optimization for wrapped
113ece8a530Spatrick     // (with --wrap) symbols because otherwise LTO would inline them while
114ece8a530Spatrick     // their values are still not final.
115ece8a530Spatrick     r.LinkerRedefined = !sym->canInline;
116ece8a530Spatrick   }
117ece8a530Spatrick   checkError(ltoObj->add(std::move(f.obj), resols));
118ece8a530Spatrick }
119ece8a530Spatrick 
120ece8a530Spatrick // Merge all the bitcode files we have seen, codegen the result
121ece8a530Spatrick // and return the resulting objects.
compile()122ece8a530Spatrick std::vector<StringRef> BitcodeCompiler::compile() {
123ece8a530Spatrick   unsigned maxTasks = ltoObj->getMaxTasks();
124ece8a530Spatrick   buf.resize(maxTasks);
125ece8a530Spatrick   files.resize(maxTasks);
126ece8a530Spatrick 
127ece8a530Spatrick   // The --thinlto-cache-dir option specifies the path to a directory in which
128ece8a530Spatrick   // to cache native object files for ThinLTO incremental builds. If a path was
129ece8a530Spatrick   // specified, configure LTO to use it as the cache directory.
130*dfe94b16Srobert   FileCache cache;
131ece8a530Spatrick   if (!config->thinLTOCacheDir.empty())
132*dfe94b16Srobert     cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
133*dfe94b16Srobert                              [&](size_t task, const Twine &moduleName,
134*dfe94b16Srobert                                  std::unique_ptr<MemoryBuffer> mb) {
135ece8a530Spatrick                                files[task] = std::move(mb);
136ece8a530Spatrick                              }));
137ece8a530Spatrick 
138ece8a530Spatrick   checkError(ltoObj->run(
139*dfe94b16Srobert       [&](size_t task, const Twine &moduleName) {
140*dfe94b16Srobert         return std::make_unique<CachedFileStream>(
141ece8a530Spatrick             std::make_unique<raw_svector_ostream>(buf[task]));
142ece8a530Spatrick       },
143ece8a530Spatrick       cache));
144ece8a530Spatrick 
145ece8a530Spatrick   if (!config->thinLTOCacheDir.empty())
146*dfe94b16Srobert     pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files);
147ece8a530Spatrick 
148ece8a530Spatrick   std::vector<StringRef> ret;
149ece8a530Spatrick   for (unsigned i = 0; i != maxTasks; ++i) {
150ece8a530Spatrick     if (buf[i].empty())
151ece8a530Spatrick       continue;
152ece8a530Spatrick     if (config->saveTemps) {
153ece8a530Spatrick       if (i == 0)
154ece8a530Spatrick         saveBuffer(buf[i], config->outputFile + ".lto.o");
155ece8a530Spatrick       else
156ece8a530Spatrick         saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
157ece8a530Spatrick     }
158ece8a530Spatrick     ret.emplace_back(buf[i].data(), buf[i].size());
159ece8a530Spatrick   }
160ece8a530Spatrick 
161ece8a530Spatrick   for (std::unique_ptr<MemoryBuffer> &file : files)
162ece8a530Spatrick     if (file)
163ece8a530Spatrick       ret.push_back(file->getBuffer());
164ece8a530Spatrick 
165ece8a530Spatrick   return ret;
166ece8a530Spatrick }
167ece8a530Spatrick 
168ece8a530Spatrick } // namespace wasm
169ece8a530Spatrick } // namespace lld
170