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-exception
6//
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(Path: modulePath, OldPrefix: ctx.arg.thinLTOPrefixReplaceOld,
40 NewPrefix: 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 (ctx.arg.relocatable)
61 c.RelocModel = std::nullopt;
62 else if (ctx.isPic)
63 c.RelocModel = Reloc::PIC_;
64 else
65 c.RelocModel = Reloc::Static;
66
67 if (ctx.arg.saveTemps)
68 checkError(e: c.addSaveTemps(OutputFileName: ctx.arg.outputFile.str() + ".",
69 /*UseInputModulePath*/ true));
70 return c;
71}
72
73namespace lld::wasm {
74
75BitcodeCompiler::BitcodeCompiler() {
76 // Initialize indexFile.
77 if (!ctx.arg.thinLTOIndexOnlyArg.empty())
78 indexFile = openFile(file: ctx.arg.thinLTOIndexOnlyArg);
79
80 // Initialize ltoObj.
81 lto::ThinBackend backend;
82 auto onIndexWrite = [&](StringRef s) { thinIndices.erase(V: s); };
83 if (ctx.arg.thinLTOIndexOnly) {
84 backend = lto::createWriteIndexesThinBackend(
85 Parallelism: llvm::hardware_concurrency(Num: ctx.arg.thinLTOJobs),
86 OldPrefix: std::string(ctx.arg.thinLTOPrefixReplaceOld),
87 NewPrefix: std::string(ctx.arg.thinLTOPrefixReplaceNew),
88 NativeObjectPrefix: std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),
89 ShouldEmitImportsFiles: ctx.arg.thinLTOEmitImportsFiles, LinkedObjectsFile: indexFile.get(), OnWrite: onIndexWrite);
90 } else {
91 backend = lto::createInProcessThinBackend(
92 Parallelism: llvm::heavyweight_hardware_concurrency(Num: ctx.arg.thinLTOJobs),
93 OnWrite: onIndexWrite, ShouldEmitIndexFiles: ctx.arg.thinLTOEmitIndexFiles,
94 ShouldEmitImportsFiles: ctx.arg.thinLTOEmitImportsFiles);
95 }
96 ltoObj = std::make_unique<lto::LTO>(args: createConfig(), args&: backend,
97 args&: ctx.arg.ltoPartitions);
98}
99
100BitcodeCompiler::~BitcodeCompiler() = default;
101
102static void undefine(Symbol *s) {
103 if (auto f = dyn_cast<DefinedFunction>(Val: s))
104 // If the signature is null, there were no calls from non-bitcode objects.
105 replaceSymbol<UndefinedFunction>(s: f, arg: f->getName(), arg: std::nullopt,
106 arg: std::nullopt, arg: 0, arg: f->getFile(),
107 arg&: f->signature, arg: f->signature != nullptr);
108 else if (isa<DefinedData>(Val: s))
109 replaceSymbol<UndefinedData>(s, arg: s->getName(), arg: 0, arg: s->getFile());
110 else
111 llvm_unreachable("unexpected symbol kind");
112}
113
114void BitcodeCompiler::add(BitcodeFile &f) {
115 lto::InputFile &obj = *f.obj;
116 unsigned symNum = 0;
117 ArrayRef<Symbol *> syms = f.getSymbols();
118 std::vector<lto::SymbolResolution> resols(syms.size());
119
120 if (ctx.arg.thinLTOEmitIndexFiles) {
121 thinIndices.insert(V: obj.getName());
122 }
123
124 // Provide a resolution to the LTO API for each symbol.
125 for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
126 Symbol *sym = syms[symNum];
127 lto::SymbolResolution &r = resols[symNum];
128 ++symNum;
129
130 // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
131 // reports two symbols for module ASM defined. Without this check, lld
132 // flags an undefined in IR with a definition in ASM as prevailing.
133 // Once IRObjectFile is fixed to report only one symbol this hack can
134 // be removed.
135 r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
136 r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||
137 sym->isNoStrip() ||
138 (r.Prevailing && sym->isExported());
139 if (r.Prevailing)
140 undefine(s: sym);
141
142 // We tell LTO to not apply interprocedural optimization for wrapped
143 // (with --wrap) symbols because otherwise LTO would inline them while
144 // their values are still not final.
145 r.LinkerRedefined = !sym->canInline;
146 }
147 checkError(e: ltoObj->add(Obj: std::move(f.obj), Res: resols));
148}
149
150// If LazyObjFile has not been added to link, emit empty index files.
151// This is needed because this is what GNU gold plugin does and we have a
152// distributed build system that depends on that behavior.
153static void thinLTOCreateEmptyIndexFiles() {
154 DenseSet<StringRef> linkedBitCodeFiles;
155 for (BitcodeFile *f : ctx.bitcodeFiles)
156 linkedBitCodeFiles.insert(V: f->getName());
157
158 for (BitcodeFile *f : ctx.lazyBitcodeFiles) {
159 if (!f->lazy)
160 continue;
161 if (linkedBitCodeFiles.contains(V: f->getName()))
162 continue;
163 std::string path =
164 replaceThinLTOSuffix(path: getThinLTOOutputFile(modulePath: f->obj->getName()));
165 std::unique_ptr<raw_fd_ostream> os = openFile(file: path + ".thinlto.bc");
166 if (!os)
167 continue;
168
169 ModuleSummaryIndex m(/*HaveGVs*/ false);
170 m.setSkipModuleByDistributedBackend();
171 writeIndexToFile(Index: m, Out&: *os);
172 if (ctx.arg.thinLTOEmitImportsFiles)
173 openFile(file: path + ".imports");
174 }
175}
176
177// Merge all the bitcode files we have seen, codegen the result
178// and return the resulting objects.
179SmallVector<InputFile *, 0> BitcodeCompiler::compile() {
180 unsigned maxTasks = ltoObj->getMaxTasks();
181 buf.resize(N: maxTasks);
182 files.resize(new_size: maxTasks);
183 filenames.resize(N: maxTasks);
184
185 // The --thinlto-cache-dir option specifies the path to a directory in which
186 // to cache native object files for ThinLTO incremental builds. If a path was
187 // specified, configure LTO to use it as the cache directory.
188 FileCache cache;
189 if (!ctx.arg.thinLTOCacheDir.empty())
190 cache = check(e: localCache(CacheNameRef: "ThinLTO", TempFilePrefixRef: "Thin", CacheDirectoryPathRef: ctx.arg.thinLTOCacheDir,
191 AddBuffer: [&](size_t task, const Twine &moduleName,
192 std::unique_ptr<MemoryBuffer> mb) {
193 files[task] = std::move(mb);
194 }));
195
196 checkError(e: ltoObj->run(
197 AddStream: [&](size_t task, const Twine &moduleName) {
198 buf[task].first = moduleName.str();
199 return std::make_unique<CachedFileStream>(
200 args: std::make_unique<raw_svector_ostream>(args&: buf[task].second));
201 },
202 Cache: cache));
203
204 // Emit empty index files for non-indexed files but not in single-module mode.
205 for (StringRef s : thinIndices) {
206 std::string path(s);
207 openFile(file: path + ".thinlto.bc");
208 if (ctx.arg.thinLTOEmitImportsFiles)
209 openFile(file: path + ".imports");
210 }
211
212 if (ctx.arg.thinLTOEmitIndexFiles)
213 thinLTOCreateEmptyIndexFiles();
214
215 if (ctx.arg.thinLTOIndexOnly) {
216 if (!ctx.arg.ltoObjPath.empty())
217 saveBuffer(buffer: buf[0].second, path: ctx.arg.ltoObjPath);
218
219 // ThinLTO with index only option is required to generate only the index
220 // files. After that, we exit from linker and ThinLTO backend runs in a
221 // distributed environment.
222 if (indexFile)
223 indexFile->close();
224 return {};
225 }
226
227 if (!ctx.arg.thinLTOCacheDir.empty())
228 pruneCache(Path: ctx.arg.thinLTOCacheDir, Policy: ctx.arg.thinLTOCachePolicy, Files: files);
229
230 SmallVector<InputFile *, 0> ret;
231 for (unsigned i = 0; i != maxTasks; ++i) {
232 StringRef objBuf = buf[i].second;
233 StringRef bitcodeFilePath = buf[i].first;
234 if (files[i]) {
235 // When files[i] is not null, we get the native relocatable file from the
236 // cache. filenames[i] contains the original BitcodeFile's identifier.
237 objBuf = files[i]->getBuffer();
238 bitcodeFilePath = filenames[i];
239 } else {
240 objBuf = buf[i].second;
241 bitcodeFilePath = buf[i].first;
242 }
243 if (objBuf.empty())
244 continue;
245
246 // If the input bitcode file is path/to/x.o and -o specifies a.out, the
247 // corresponding native relocatable file path will look like:
248 // path/to/a.out.lto.x.o.
249 StringRef ltoObjName;
250 if (bitcodeFilePath == "ld-temp.o") {
251 ltoObjName =
252 saver().save(S: Twine(ctx.arg.outputFile) + ".lto" +
253 (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o");
254 } else {
255 StringRef directory = sys::path::parent_path(path: bitcodeFilePath);
256 // For an archive member, which has an identifier like "d/a.a(coll.o at
257 // 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use
258 // the stem (d/a.o => a).
259 StringRef baseName = bitcodeFilePath.ends_with(Suffix: ")")
260 ? sys::path::filename(path: bitcodeFilePath)
261 : sys::path::stem(path: bitcodeFilePath);
262 StringRef outputFileBaseName = sys::path::filename(path: ctx.arg.outputFile);
263 SmallString<256> path;
264 sys::path::append(path, a: directory,
265 b: outputFileBaseName + ".lto." + baseName + ".o");
266 sys::path::remove_dots(path, remove_dot_dot: true);
267 ltoObjName = saver().save(S: path.str());
268 }
269 if (ctx.arg.saveTemps)
270 saveBuffer(buffer: objBuf, path: ltoObjName);
271 ret.emplace_back(Args: createObjectFile(mb: MemoryBufferRef(objBuf, ltoObjName)));
272 }
273
274 if (!ctx.arg.ltoObjPath.empty()) {
275 saveBuffer(buffer: buf[0].second, path: ctx.arg.ltoObjPath);
276 for (unsigned i = 1; i != maxTasks; ++i)
277 saveBuffer(buffer: buf[i].second, path: ctx.arg.ltoObjPath + Twine(i));
278 }
279
280 return ret;
281}
282
283} // namespace lld::wasm
284

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lld/wasm/LTO.cpp