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 (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 that
68 // external symbols are references via the GOT.
69 // TODO(sbc): This should probably be Reloc::DynamicNoPIC, but the backend
70 // doesn't currently support that.
71 c.RelocModel = Reloc::PIC_;
72 else
73 c.RelocModel = Reloc::Static;
74
75 if (ctx.arg.saveTemps)
76 checkError(e: c.addSaveTemps(OutputFileName: 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(file: ctx.arg.thinLTOIndexOnlyArg);
87
88 // Initialize ltoObj.
89 lto::ThinBackend backend;
90 auto onIndexWrite = [&](StringRef s) { thinIndices.erase(V: s); };
91 if (ctx.arg.thinLTOIndexOnly) {
92 backend = lto::createWriteIndexesThinBackend(
93 Parallelism: llvm::hardware_concurrency(Num: ctx.arg.thinLTOJobs),
94 OldPrefix: std::string(ctx.arg.thinLTOPrefixReplaceOld),
95 NewPrefix: std::string(ctx.arg.thinLTOPrefixReplaceNew),
96 NativeObjectPrefix: std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),
97 ShouldEmitImportsFiles: ctx.arg.thinLTOEmitImportsFiles, LinkedObjectsFile: indexFile.get(), OnWrite: onIndexWrite);
98 } else {
99 backend = lto::createInProcessThinBackend(
100 Parallelism: llvm::heavyweight_hardware_concurrency(Num: ctx.arg.thinLTOJobs),
101 OnWrite: onIndexWrite, ShouldEmitIndexFiles: ctx.arg.thinLTOEmitIndexFiles,
102 ShouldEmitImportsFiles: ctx.arg.thinLTOEmitImportsFiles);
103 }
104 ltoObj = std::make_unique<lto::LTO>(args: createConfig(), args&: backend,
105 args&: ctx.arg.ltoPartitions);
106}
107
108BitcodeCompiler::~BitcodeCompiler() = default;
109
110static void undefine(Symbol *s) {
111 if (auto f = dyn_cast<DefinedFunction>(Val: s))
112 // If the signature is null, there were no calls from non-bitcode objects.
113 replaceSymbol<UndefinedFunction>(s: f, arg: f->getName(), arg: std::nullopt,
114 arg: std::nullopt, arg: 0, arg: f->getFile(),
115 arg&: f->signature, arg: f->signature != nullptr);
116 else if (isa<DefinedData>(Val: s))
117 replaceSymbol<UndefinedData>(s, arg: s->getName(), arg: 0, arg: s->getFile());
118 else
119 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(V: 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 IRObjectFile
139 // reports two symbols for module ASM defined. Without this check, lld
140 // flags an undefined in IR with a definition in ASM as prevailing.
141 // Once IRObjectFile is fixed to report only one symbol this hack can
142 // 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(s: sym);
149
150 // We tell LTO to not apply interprocedural optimization for wrapped
151 // (with --wrap) symbols because otherwise LTO would inline them while
152 // their values are still not final.
153 r.LinkerRedefined = !sym->canInline;
154 }
155 checkError(e: ltoObj->add(Obj: std::move(f.obj), Res: 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 a
160// distributed build system that depends on that behavior.
161static void thinLTOCreateEmptyIndexFiles() {
162 DenseSet<StringRef> linkedBitCodeFiles;
163 for (BitcodeFile *f : ctx.bitcodeFiles)
164 linkedBitCodeFiles.insert(V: f->getName());
165
166 for (BitcodeFile *f : ctx.lazyBitcodeFiles) {
167 if (!f->lazy)
168 continue;
169 if (linkedBitCodeFiles.contains(V: f->getName()))
170 continue;
171 std::string path =
172 replaceThinLTOSuffix(path: getThinLTOOutputFile(modulePath: f->obj->getName()));
173 std::unique_ptr<raw_fd_ostream> os = openFile(file: path + ".thinlto.bc");
174 if (!os)
175 continue;
176
177 ModuleSummaryIndex m(/*HaveGVs*/ false);
178 m.setSkipModuleByDistributedBackend();
179 writeIndexToFile(Index: m, Out&: *os);
180 if (ctx.arg.thinLTOEmitImportsFiles)
181 openFile(file: path + ".imports");
182 }
183}
184
185// Merge all the bitcode files we have seen, codegen the result
186// and return the resulting objects.
187SmallVector<InputFile *, 0> BitcodeCompiler::compile() {
188 unsigned maxTasks = ltoObj->getMaxTasks();
189 buf.resize(N: maxTasks);
190 files.resize(new_size: maxTasks);
191 filenames.resize(N: maxTasks);
192
193 // The --thinlto-cache-dir option specifies the path to a directory in which
194 // to cache native object files for ThinLTO incremental builds. If a path was
195 // specified, configure LTO to use it as the cache directory.
196 FileCache cache;
197 if (!ctx.arg.thinLTOCacheDir.empty())
198 cache = check(e: localCache(CacheNameRef: "ThinLTO", TempFilePrefixRef: "Thin", CacheDirectoryPathRef: ctx.arg.thinLTOCacheDir,
199 AddBuffer: [&](size_t task, const Twine &moduleName,
200 std::unique_ptr<MemoryBuffer> mb) {
201 files[task] = std::move(mb);
202 }));
203
204 checkError(e: ltoObj->run(
205 AddStream: [&](size_t task, const Twine &moduleName) {
206 buf[task].first = moduleName.str();
207 return std::make_unique<CachedFileStream>(
208 args: std::make_unique<raw_svector_ostream>(args&: buf[task].second));
209 },
210 Cache: 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(file: path + ".thinlto.bc");
216 if (ctx.arg.thinLTOEmitImportsFiles)
217 openFile(file: 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(buffer: buf[0].second, path: ctx.arg.ltoObjPath);
226
227 // ThinLTO with index only option is required to generate only the index
228 // files. After that, we exit from linker and ThinLTO backend runs in a
229 // distributed environment.
230 if (indexFile)
231 indexFile->close();
232 return {};
233 }
234
235 if (!ctx.arg.thinLTOCacheDir.empty())
236 pruneCache(Path: ctx.arg.thinLTOCacheDir, Policy: ctx.arg.thinLTOCachePolicy, Files: 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 the
244 // 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, the
255 // 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(S: Twine(ctx.arg.outputFile) + ".lto" +
261 (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o");
262 } else {
263 StringRef directory = sys::path::parent_path(path: bitcodeFilePath);
264 // For an archive member, which has an identifier like "d/a.a(coll.o at
265 // 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use
266 // the stem (d/a.o => a).
267 StringRef baseName = bitcodeFilePath.ends_with(Suffix: ")")
268 ? sys::path::filename(path: bitcodeFilePath)
269 : sys::path::stem(path: bitcodeFilePath);
270 StringRef outputFileBaseName = sys::path::filename(path: ctx.arg.outputFile);
271 SmallString<256> path;
272 sys::path::append(path, a: directory,
273 b: outputFileBaseName + ".lto." + baseName + ".o");
274 sys::path::remove_dots(path, remove_dot_dot: true);
275 ltoObjName = saver().save(S: path.str());
276 }
277 if (ctx.arg.saveTemps)
278 saveBuffer(buffer: objBuf, path: ltoObjName);
279 ret.emplace_back(Args: createObjectFile(mb: MemoryBufferRef(objBuf, ltoObjName)));
280 }
281
282 if (!ctx.arg.ltoObjPath.empty()) {
283 saveBuffer(buffer: buf[0].second, path: ctx.arg.ltoObjPath);
284 for (unsigned i = 1; i != maxTasks; ++i)
285 saveBuffer(buffer: buf[i].second, path: ctx.arg.ltoObjPath + Twine(i));
286 }
287
288 return ret;
289}
290
291} // namespace lld::wasm
292