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