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