xref: /llvm-project/lld/wasm/LTO.cpp (revision 3792b36234b6c87d728f0a905543e284bf961460)
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/Args.h"
14 #include "lld/Common/CommonLinkerContext.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Filesystem.h"
17 #include "lld/Common/Strings.h"
18 #include "lld/Common/TargetOptionsCommandFlags.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/ADT/Twine.h"
23 #include "llvm/Bitcode/BitcodeWriter.h"
24 #include "llvm/IR/DiagnosticPrinter.h"
25 #include "llvm/LTO/Config.h"
26 #include "llvm/LTO/LTO.h"
27 #include "llvm/Object/SymbolicFile.h"
28 #include "llvm/Support/Caching.h"
29 #include "llvm/Support/CodeGen.h"
30 #include "llvm/Support/Error.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/MemoryBuffer.h"
33 #include "llvm/Support/Path.h"
34 #include "llvm/Support/raw_ostream.h"
35 #include <algorithm>
36 #include <cstddef>
37 #include <memory>
38 #include <string>
39 #include <system_error>
40 #include <vector>
41 
42 using namespace llvm;
43 using namespace lld::wasm;
44 using namespace lld;
45 
46 static std::string getThinLTOOutputFile(StringRef modulePath) {
47   return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld,
48                                    ctx.arg.thinLTOPrefixReplaceNew);
49 }
50 
51 static lto::Config createConfig() {
52   lto::Config c;
53   c.Options = initTargetOptionsFromCodeGenFlags();
54 
55   // Always emit a section per function/data with LTO.
56   c.Options.FunctionSections = true;
57   c.Options.DataSections = true;
58 
59   c.DisableVerify = ctx.arg.disableVerify;
60   c.DiagHandler = diagnosticHandler;
61   c.OptLevel = ctx.arg.ltoo;
62   c.MAttrs = getMAttrs();
63   c.CGOptLevel = ctx.arg.ltoCgo;
64   c.DebugPassManager = ctx.arg.ltoDebugPassManager;
65   c.AlwaysEmitRegularLTOObj = !ctx.arg.ltoObjPath.empty();
66 
67   if (ctx.arg.relocatable)
68     c.RelocModel = std::nullopt;
69   else if (ctx.isPic)
70     c.RelocModel = Reloc::PIC_;
71   else
72     c.RelocModel = Reloc::Static;
73 
74   if (ctx.arg.saveTemps)
75     checkError(c.addSaveTemps(ctx.arg.outputFile.str() + ".",
76                               /*UseInputModulePath*/ true));
77   return c;
78 }
79 
80 namespace lld::wasm {
81 
82 BitcodeCompiler::BitcodeCompiler() {
83   // Initialize indexFile.
84   if (!ctx.arg.thinLTOIndexOnlyArg.empty())
85     indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg);
86 
87   // Initialize ltoObj.
88   lto::ThinBackend backend;
89   auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); };
90   if (ctx.arg.thinLTOIndexOnly) {
91     backend = lto::createWriteIndexesThinBackend(
92         llvm::hardware_concurrency(ctx.arg.thinLTOJobs),
93         std::string(ctx.arg.thinLTOPrefixReplaceOld),
94         std::string(ctx.arg.thinLTOPrefixReplaceNew),
95         std::string(ctx.arg.thinLTOPrefixReplaceNativeObject),
96         ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);
97   } else {
98     backend = lto::createInProcessThinBackend(
99         llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs),
100         onIndexWrite, ctx.arg.thinLTOEmitIndexFiles,
101         ctx.arg.thinLTOEmitImportsFiles);
102   }
103   ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,
104                                       ctx.arg.ltoPartitions);
105 }
106 
107 BitcodeCompiler::~BitcodeCompiler() = default;
108 
109 static void undefine(Symbol *s) {
110   if (auto f = dyn_cast<DefinedFunction>(s))
111     replaceSymbol<UndefinedFunction>(f, f->getName(), std::nullopt,
112                                      std::nullopt, 0, f->getFile(),
113                                      f->signature);
114   else if (isa<DefinedData>(s))
115     replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile());
116   else
117     llvm_unreachable("unexpected symbol kind");
118 }
119 
120 void BitcodeCompiler::add(BitcodeFile &f) {
121   lto::InputFile &obj = *f.obj;
122   unsigned symNum = 0;
123   ArrayRef<Symbol *> syms = f.getSymbols();
124   std::vector<lto::SymbolResolution> resols(syms.size());
125 
126   if (ctx.arg.thinLTOEmitIndexFiles) {
127     thinIndices.insert(obj.getName());
128   }
129 
130   // Provide a resolution to the LTO API for each symbol.
131   for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
132     Symbol *sym = syms[symNum];
133     lto::SymbolResolution &r = resols[symNum];
134     ++symNum;
135 
136     // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
137     // reports two symbols for module ASM defined. Without this check, lld
138     // flags an undefined in IR with a definition in ASM as prevailing.
139     // Once IRObjectFile is fixed to report only one symbol this hack can
140     // be removed.
141     r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
142     r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||
143                             sym->isNoStrip() ||
144                             (r.Prevailing && sym->isExported());
145     if (r.Prevailing)
146       undefine(sym);
147 
148     // We tell LTO to not apply interprocedural optimization for wrapped
149     // (with --wrap) symbols because otherwise LTO would inline them while
150     // their values are still not final.
151     r.LinkerRedefined = !sym->canInline;
152   }
153   checkError(ltoObj->add(std::move(f.obj), resols));
154 }
155 
156 // If LazyObjFile has not been added to link, emit empty index files.
157 // This is needed because this is what GNU gold plugin does and we have a
158 // distributed build system that depends on that behavior.
159 static void thinLTOCreateEmptyIndexFiles() {
160   DenseSet<StringRef> linkedBitCodeFiles;
161   for (BitcodeFile *f : ctx.bitcodeFiles)
162     linkedBitCodeFiles.insert(f->getName());
163 
164   for (BitcodeFile *f : ctx.lazyBitcodeFiles) {
165     if (!f->lazy)
166       continue;
167     if (linkedBitCodeFiles.contains(f->getName()))
168       continue;
169     std::string path =
170         replaceThinLTOSuffix(getThinLTOOutputFile(f->obj->getName()));
171     std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");
172     if (!os)
173       continue;
174 
175     ModuleSummaryIndex m(/*HaveGVs*/ false);
176     m.setSkipModuleByDistributedBackend();
177     writeIndexToFile(m, *os);
178     if (ctx.arg.thinLTOEmitImportsFiles)
179       openFile(path + ".imports");
180   }
181 }
182 
183 // Merge all the bitcode files we have seen, codegen the result
184 // and return the resulting objects.
185 std::vector<StringRef> BitcodeCompiler::compile() {
186   unsigned maxTasks = ltoObj->getMaxTasks();
187   buf.resize(maxTasks);
188   files.resize(maxTasks);
189 
190   // The --thinlto-cache-dir option specifies the path to a directory in which
191   // to cache native object files for ThinLTO incremental builds. If a path was
192   // specified, configure LTO to use it as the cache directory.
193   FileCache cache;
194   if (!ctx.arg.thinLTOCacheDir.empty())
195     cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir,
196                              [&](size_t task, const Twine &moduleName,
197                                  std::unique_ptr<MemoryBuffer> mb) {
198                                files[task] = std::move(mb);
199                              }));
200 
201   checkError(ltoObj->run(
202       [&](size_t task, const Twine &moduleName) {
203         buf[task].first = moduleName.str();
204         return std::make_unique<CachedFileStream>(
205             std::make_unique<raw_svector_ostream>(buf[task].second));
206       },
207       cache));
208 
209   // Emit empty index files for non-indexed files but not in single-module mode.
210   for (StringRef s : thinIndices) {
211     std::string path(s);
212     openFile(path + ".thinlto.bc");
213     if (ctx.arg.thinLTOEmitImportsFiles)
214       openFile(path + ".imports");
215   }
216 
217   if (ctx.arg.thinLTOEmitIndexFiles)
218     thinLTOCreateEmptyIndexFiles();
219 
220   if (ctx.arg.thinLTOIndexOnly) {
221     if (!ctx.arg.ltoObjPath.empty())
222       saveBuffer(buf[0].second, ctx.arg.ltoObjPath);
223 
224     // ThinLTO with index only option is required to generate only the index
225     // files. After that, we exit from linker and ThinLTO backend runs in a
226     // distributed environment.
227     if (indexFile)
228       indexFile->close();
229     return {};
230   }
231 
232   if (!ctx.arg.thinLTOCacheDir.empty())
233     pruneCache(ctx.arg.thinLTOCacheDir, ctx.arg.thinLTOCachePolicy, files);
234 
235   std::vector<StringRef> ret;
236   for (unsigned i = 0; i != maxTasks; ++i) {
237     StringRef objBuf = buf[i].second;
238     StringRef bitcodeFilePath = buf[i].first;
239     if (objBuf.empty())
240       continue;
241     ret.emplace_back(objBuf.data(), objBuf.size());
242     if (!ctx.arg.saveTemps)
243       continue;
244 
245     // If the input bitcode file is path/to/x.o and -o specifies a.out, the
246     // corresponding native relocatable file path will look like:
247     // path/to/a.out.lto.x.o.
248     StringRef ltoObjName;
249     if (bitcodeFilePath == "ld-temp.o") {
250       ltoObjName =
251           saver().save(Twine(ctx.arg.outputFile) + ".lto" +
252                        (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o");
253     } else {
254       StringRef directory = sys::path::parent_path(bitcodeFilePath);
255       // For an archive member, which has an identifier like "d/a.a(coll.o at
256       // 8)" (see BitcodeFile::BitcodeFile), use the filename; otherwise, use
257       // the stem (d/a.o => a).
258       StringRef baseName = bitcodeFilePath.ends_with(")")
259                                ? sys::path::filename(bitcodeFilePath)
260                                : sys::path::stem(bitcodeFilePath);
261       StringRef outputFileBaseName = sys::path::filename(ctx.arg.outputFile);
262       SmallString<256> path;
263       sys::path::append(path, directory,
264                         outputFileBaseName + ".lto." + baseName + ".o");
265       sys::path::remove_dots(path, true);
266       ltoObjName = saver().save(path.str());
267     }
268     saveBuffer(objBuf, ltoObjName);
269   }
270 
271   if (!ctx.arg.ltoObjPath.empty()) {
272     saveBuffer(buf[0].second, ctx.arg.ltoObjPath);
273     for (unsigned i = 1; i != maxTasks; ++i)
274       saveBuffer(buf[i].second, ctx.arg.ltoObjPath + Twine(i));
275   }
276 
277   for (std::unique_ptr<MemoryBuffer> &file : files)
278     if (file)
279       ret.push_back(file->getBuffer());
280 
281   return ret;
282 }
283 
284 } // namespace lld::wasm
285